Toon posts:

[OO]discussie

Pagina: 1
Acties:
  • 174 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Ik heb nu al een paar dagen een discussie lopen met wat mensen op het werk over het begrip inheritance. Deze heren hebben een heel unieke kijk op het concept. Ik wil mensen vragen die thuis zijn in de materie, en het liefst er ervaring mee hebben qua design/implementatie, eens te reageren op onderstaande. Graag zoveel mogelijk onderbouwing natuurlijk.

Hier komt het probleem:
We hebben 3 classes, Person, Man en Woman. Vanzelfsprekend erven Man en Woman van Person, en hebben daarnaast nog wat attributen. Voor het gemak maar een slordig paintbrush plaatje.

Afbeeldingslocatie: http://sheila.yi.org/ash/temp/blaat.jpg

Alleen Man heeft dus een secret, en alleen een vrouw heeft kinderen. Vraag me niet waarom, het gaat ff om het voorbeeld.
De discussie gaat nu eigenlijk over wie de functie GetSecret() moet gaan implementeren

Hun stelling:
Omdat in het echte leven Person een verzameling van mannen en vrouwen is, immers een persoon is altijd een man of vrouw, is het object Person ook de verzameling van Man en Woman. Met andere woorden, Person moet de implementatie leveren van GetSecret() (en ook van GetNrOfChildren() uiteindelijk). Als iemand een object van type Person heeft, en GetSecret() roept, zal dit object zichzelf gaan downcasten naar Man en de secret returnen.

Mijn stelling:
Juist niet, secret is specifiek voor Man, dus daar heeft Person niks mee te maken. Sterker nog, het druist zo'n beetje tegen alle regels in die met OO te maken hebben. Derhalve moet Man de implementatie van GetSecret() leveren.

Ik heb al wat argumenten liggen van beide partijen, maar die geef ik nog ff niet, ik wil graag eerst wat reacties hebben.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Jij hebt gelijk. Zolang het concept 'secret' bij Man geintroduceerd wordt is hij de enige die verantwoordelijkheid heeft om het te kunnen getten: de getter zou geen nut hebben in Person. Tenzij je met dynamische 'attributen' wil gaan werken die je in Person introduceert, maar dat is a) advanced topic en b) in dit geval nutteloos.

Professionele website nodig?


  • whoami
  • Registratie: December 2000
  • Laatst online: 01:57
Mjah, er is natuurlijk wel wat voor te zeggen over die stelling dat, als je een Person object hebt waar je een 'Man' instopt, dat je dan zonder casten die GetSecret() kunt aanroepen. (Mits het een virtuele functie is dan).

Echter vind ik het persoonlijk zelf niet ook niet zo mooi om die nrOfChildren en Secret in Person te stoppen als die echt volledig afhankelijk zijn van Man en Woman.
Aangezien Secret een specialisatie is voor een 'Man' en nrOfChildren een specifiek ding is voor vrouwen, zou ik het ook in de respectievelijke Man en Woman classes steken.

[ Voor 19% gewijzigd door whoami op 07-06-2003 17:50 ]

https://fgheysels.github.io/


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Er zijn ontwerpparadigma (oa het compositepattern meen ik) waar het inderdaad in Person gedaan zou worden, maar dan wel als een abstracte methode of een methode die standaard 0 of -1 ofzo teruggeeft en dus in de desbetreffende objecten overriden "moet" worden.

Anderzijds zou je ook kunnen beargumenteren dat het idd bij man of woman hoort en dus ook daar gedefinieerd en geimplementeerd wordt.
Het hangt denk ik heel sterk af van hoe je de boel later weer aanroept. Het is wat loos als je steeds overal een if ala "if(objectX instanceof Man)" moet neerzetten :)

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:57
ACM schreef op 07 juni 2003 @ 17:54:
Er zijn ontwerpparadigma (oa het compositepattern meen ik) waar het inderdaad in Person gedaan zou worden, maar dan wel als een abstracte methode of een methode die standaard 0 of -1 ofzo teruggeeft en dus in de desbetreffende objecten overriden "moet" worden.
Idd, maar in dat pattern is het wel nodig, omdat bepaalde objecten andere objecten kunnen bevatten met dezelfde interface, en ze daarom dus wel moeten hebben. (Anders voldoen ze niet meer ad interface)

Hier zie ik niet echt het nut in om die members in Person te gaan implementeren, tenzij je idd veel zou moeten gaan casten anders....

[ Voor 8% gewijzigd door whoami op 07-06-2003 18:04 ]

https://fgheysels.github.io/


  • Robtimus
  • Registratie: November 2002
  • Laatst online: 19:33

Robtimus

me Robtimus no like you

Verwijderd schreef op 07 juni 2003 @ 17:46:
Hun stelling:
Omdat in het echte leven Person een verzameling van mannen en vrouwen is, immers een persoon is altijd een man of vrouw, is het object Person ook de verzameling van Man en Woman. Met andere woorden, Person moet de implementatie leveren van GetSecret() (en ook van GetNrOfChildren() uiteindelijk). Als iemand een object van type Person heeft, en GetSecret() roept, zal dit object zichzelf gaan downcasten naar Man en de secret returnen.
Ik zie dit al voor me: ze hebben een object van type Woman (dus ook van type Person). Vervolgens roepen ze GetSecret() aan. Gevolg: het wordt gedowncast naar Man en voila, error!

* Robtimus is er ook zwaar voorstander voor het pas te declareren zodra het nodig is, dus in Man/Woman

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • whoami
  • Registratie: December 2000
  • Laatst online: 01:57
IceManX schreef op 07 juni 2003 @ 18:13:
[...]
Ik zie dit al voor me: ze hebben een object van type Woman (dus ook van type Person). Vervolgens roepen ze GetSecret() aan. Gevolg: het wordt gedowncast naar Man en voila, error!
Nee hoor....
Als GetSecret() als een virtuele (of abstracte) functie gedefinieerd is in Person, dan kan je perfect het volgende doen:

C#:
1
2
Person eenPersoon = new Woman();
eenPersoon.GetSecret();


Aangezien GetSecret een virtuele functie is in Person, kent Woman ook deze functie.
Dit is gewoon niets meer dan polymorphisme. Als je de GetSecret method ook in Woman hebt geoverrided, dan zal de GetSecret code in Woman uitgevoerd worden. Heb je dat niet gedaan, dan zal de GetSecret code van Person uitgevoerd worden.

https://fgheysels.github.io/


Verwijderd

Ik hou mij meestal uit dit gedoe van inheriting enzo (omdat het gewoon soms zover gaat :() maar het meest logische lijkt mij jouw uitleg!
Ander voorbeeldje:
Sporters
| |
lopers ----------- jeux de boulers ;)

aantaltoertjespermin --------- aantalwinnende ballen (ofzo)

Nu kan je toch moeilijk aan al je sporters vragen hoeveel toertjes per minuut ze lopen :)

Het gaat natuurlijk via veel hersenkronkels wel in OO programming maar ik hou van simpele logische programma's.

[ Voor 3% gewijzigd door Verwijderd op 07-06-2003 18:25 ]


Verwijderd

Topicstarter
De enige reden voor deze aanpak die ik kan verzinnen is de volgende:
Stel je werkt met een bepaalde collectie van Persons. Je kunt dan zonder downcasten meteen GetSecret() aanroepen. Maar dan wil ik het wel es hebben over de gevolgen voor:

1) onderhoudbaarheid: als je een subclass toevoegt, bijvoorbeeld Child, stel je zou die apart willen onderscheiden van Man of Woman, dan moet je ook je baseclass Person aanpassen, hij moet zich immers kunnen downcasten naar Child. Als je nu in een ander geval niet 3 maar zeg 15 subclasses hebt, gaat dit erg onhandig worden.

2) netheid van je code: je krijgt in je baseclass Person zo'n constructie:
if (instanceof(a)
else if (instanceof(b)
else if (... etc ...)

3) dubbelzinnigheid: laten we stellen dat een Child ook een secret kan hebben, en je zit in Person, naar wie moet ik mezelf dan downcasten?

Verwijderd

Topicstarter
whoami schreef op 07 juni 2003 @ 18:17:
[...]

Nee hoor....
Als GetSecret() als een virtuele (of abstracte) functie gedefinieerd is in Person, dan kan je perfect het volgende doen:

C#:
1
2
Person eenPersoon = new Woman();
eenPersoon.GetSecret();


Aangezien GetSecret een virtuele functie is in Person, kent Woman ook deze functie.
Dit is gewoon niets meer dan polymorphisme. Als je de GetSecret method ook in Woman hebt geoverrided, dan zal de GetSecret code in Woman uitgevoerd worden. Heb je dat niet gedaan, dan zal de GetSecret code van Person uitgevoerd worden.
Volgens mij heb je het daar mis. Stel je voor dat ik een collectie van mensen wil hebben. Dan zal ik die collectie moeten declareren als een collectie van Persons. En nu ga ik itereren over deze collectie. Ik pak dus het eerste object uit de collectie (van type Person dus), en ik zeg GetSecret(). Nu weet het object niet waar die de implementatie van GetSecret() vandaan moet halen en zal derhalve de GetSecret() van Person aanroepen, die geeft dus een of ander NULL waarde terug. Dit is niet wat je wil. Probleem is gewoon dat je als baseclass niet opgezadeld wilt zitten met allerlei pure virtual functies, simpel en alleen omdat een van je subclasses deze wel es zou kunnen implementeren.

Ik gebruik hierbij het voorbeeld Zoogdier. Moet ik op het niveau van Zoogdier de functie GetTrunkLength() declareren, want ja, ik zou wel es een olifant kunnen zijn. Mij lijkt dit conceptueel gezien.. ehm.. op zijn zachtst gezegd.. ehm.. van de pot gerukt :P

[ Voor 17% gewijzigd door Verwijderd op 07-06-2003 18:45 ]


  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
tis altijd wikken en wegen he, je zou kunnen stellen dat je altijd een getSecret() en getChildren() op een persoon. De ene geeft altijd 0 terug enzo. Maar als alleen een Man het heeft dan is dit te gek. Er is geen echt goede keuze in dit geval: het is gewoon wat het beste past in de rest van jullie spul. Als je met person classes werkt vind ik persoonlijk dat daar alleen spul over persons in mag staan. Als je gaat compositen dan werk je meer C-achtig: dus bijvoorbeeld een member van persoon is bijvoorbeeld: sex. enzovoorts. Ik zou zoals jij het doet doen ( ;) ) want dat is het enige logische (als je later dan moet gaan instanceof of casten dan is dat maar zo, je data is altijd correct)

Verwijderd

Topicstarter
whoami schreef op 07 June 2003 @ 18:03:
[...]

Idd, maar in dat pattern is het wel nodig, omdat bepaalde objecten andere objecten kunnen bevatten met dezelfde interface, en ze daarom dus wel moeten hebben. (Anders voldoen ze niet meer ad interface)

Hier zie ik niet echt het nut in om die members in Person te gaan implementeren, tenzij je idd veel zou moeten gaan casten anders....
Klopt maar daar zit een verschil in de relatie. In DCOM heb je constructies waar het ene object binnen een ander object zit, waardoor je de interface van het binnenste object ook wil aanbieden op het buitenste object. Dit is echter een aggregatie en geen specialisatie, immers het geaggregeerde object is geen specialisatie van het buitenste object. Dit is een heel belangrijk verschil dat mensen (begrijpelijk, want het is best abstract allemaal) vaak over het hoofd zien.

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Die collega's van jou halen dingen doorelkaar. Een class is op zich een type, maar heeft meerdere gezichten, meerdere types. Een class 'person' heeft, wanneerhij geen interfaces implementeert, 1 type, 'person'. De class 'man' heeft 2 types: 'man' en 'person'. Een collectie van persons is een collectie van objects van het type 'person'. Classes 'person', 'man' en 'vrouw' voldoen hieraan.

In je code werk je dus met types. Wil je eerst een collectie van het type 'person' maken en daarna kijken welke 'man' zijn, dan lukt je dat niet. Dat is logisch, want de collectie van 'person's snapt alleen het type 'person', en downcasting naar 'man' is niet zo geweldig. (downcasting in het algemeen is niet zo best).

Een GOED model, plaatst eigenschappen van een zeker type ook in dat type, mits een type dat als basis voor dat type wordt gebruikt (dus 'person' in het geval van 'man') die eigenschappen al aandraagt (basisbeginsel inheritence). In je 'person' type plaats je dus alle eigenschappen van 'person'. In de derived classes, 'man' en 'vrouw' plaats je dus eigenschappen die NIET bij person horen, want ze gelden bv niet voor ALLE instances van dat type, maar wel bij dat type, m.a.w. ze worden niet aangedragen door het basistype 'person' en moeten dus daar geplaatst worden. In jouw model is 'geslacht' dus een eigenschap van het type 'person' en penislengte een eigenschap van het type 'man' en niet van het type 'person'.

Zoook met methods. Een type 'person' KAN geen 'getSecret()' method hebben, want het type person kent het concept 'secret' niet. Dat is gedefinieerd in het type 'man'. Je kunt dus geen polymorphism gebruiken hiervoor noch een abstract method wiens code wordt 'ingeplugged' door een inherited type, want het gaat om een eigenschap die person niet kent.

Een method die WEL in person geimplementeerd zou kunnen worden is bv een berekening die voor een man anders is dan voor een vrouw, bv of de bloeddruk nog goed is of niet. Je implementeert dan een abstract method in 'person' (of virtual als je person ook als instances wilt gebruiken, maar dat lijkt me redelijk zinloos) en die wordt geimplementeerd in zowel 'man' als 'vrouw'. Die is dan beschikbaar in een collection van het type 'person'.

ZO maak je OO modellen, niet middels Mien-uut-Ass'n geneuzel over 'een groep mensen is een groep persons en dus moeten alle eigenschappen die je wilt weten die in de man OF de vrouw zitten worden geplaatst in person'. Zo werkt het niet, want er is geen theoretische basis voor.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

ik heb geleerd ivm die dingen in database termen te denken. Je hebt dan entiteiten net als objecten. Person> man en vrouw, en secret is dan een attribuut van man, en children zijn dan relaties met vrouw.
Dus dan zie je ook mooi waar je functies dienen te komen. En ik denk dat dat een makkelijke manier van denken is...misschien eenzijdig, maar toch...

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op 07 June 2003 @ 18:57:
Klopt maar daar zit een verschil in de relatie. In DCOM heb je constructies waar het ene object binnen een ander object zit, waardoor je de interface van het binnenste object ook wil aanbieden op het buitenste object. Dit is echter een aggregatie en geen specialisatie, immers het geaggregeerde object is geen specialisatie van het buitenste object. Dit is een heel belangrijk verschil dat mensen (begrijpelijk, want het is best abstract allemaal) vaak over het hoofd zien.
Allemaal leuk maar jij praat in de topicstart over inheritence, niet over aggregation. Als je person een aggregated object wilt maken, dan moet je dat doen, maar niet praten over inheritence, want dat heeft er niets mee te maken. COM is overigens niet OO, maar component oriented. Dat is wat anders, het ondersteunt nl. geen inheritence en polymorphism (al is dat laatste met vtable knoeiwerk wel te realiseren).

Aggregation komt nog zelden voor buiten de COM wereld, behalve in code waar proxy of adapter patterns worden gebruikt.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op 07 June 2003 @ 19:11:
ik heb geleerd ivm die dingen in database termen te denken. Je hebt dan entiteiten net als objecten. Person> man en vrouw, en secret is dan een attribuut van man, en children zijn dan relaties met vrouw.
Dus dan zie je ook mooi waar je functies dienen te komen. En ik denk dat dat een makkelijke manier van denken is...misschien eenzijdig, maar toch...
Dit gaat mis :) Man en vrouw zijn subtypes van 'person'. Je hebt dan wel attributes in 'man' die niet in 'person' zitten, maar als je de NIAM regels volgt, moet je 'man' en 'vrouw' terugmappen in 'person' en die als entiteit in de database opnemen (met zo'n ranzige 'type' attribute)., OF je moet 3 tables maken: person, man en vrouw, maar dat is een hell in queries.

Het probleem zit hem in het feit dat je in relaties geen supertypes kunt meenemen, althans niet in de database zelf, de relaties hebben altijd betrekking op subtypes.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

Topicstarter
EfBe schreef op 07 June 2003 @ 19:08:
Die collega's van jou halen dingen doorelkaar. Een class is op zich een type, maar heeft meerdere gezichten, meerdere types. Een class 'person' heeft, wanneerhij geen interfaces implementeert, 1 type, 'person'. De class 'man' heeft 2 types: 'man' en 'person'. Een collectie van persons is een collectie van objects van het type 'person'. Classes 'person', 'man' en 'vrouw' voldoen hieraan.

In je code werk je dus met types. Wil je eerst een collectie van het type 'person' maken en daarna kijken welke 'man' zijn, dan lukt je dat niet. Dat is logisch, want de collectie van 'person's snapt alleen het type 'person', en downcasting naar 'man' is niet zo geweldig. (downcasting in het algemeen is niet zo best).

Een GOED model, plaatst eigenschappen van een zeker type ook in dat type, mits een type dat als basis voor dat type wordt gebruikt (dus 'person' in het geval van 'man') die eigenschappen al aandraagt (basisbeginsel inheritence). In je 'person' type plaats je dus alle eigenschappen van 'person'. In de derived classes, 'man' en 'vrouw' plaats je dus eigenschappen die NIET bij person horen, want ze gelden bv niet voor ALLE instances van dat type, maar wel bij dat type, m.a.w. ze worden niet aangedragen door het basistype 'person' en moeten dus daar geplaatst worden. In jouw model is 'geslacht' dus een eigenschap van het type 'person' en penislengte een eigenschap van het type 'man' en niet van het type 'person'.

Zoook met methods. Een type 'person' KAN geen 'getSecret()' method hebben, want het type person kent het concept 'secret' niet. Dat is gedefinieerd in het type 'man'. Je kunt dus geen polymorphism gebruiken hiervoor noch een abstract method wiens code wordt 'ingeplugged' door een inherited type, want het gaat om een eigenschap die person niet kent.

Een method die WEL in person geimplementeerd zou kunnen worden is bv een berekening die voor een man anders is dan voor een vrouw, bv of de bloeddruk nog goed is of niet. Je implementeert dan een abstract method in 'person' (of virtual als je person ook als instances wilt gebruiken, maar dat lijkt me redelijk zinloos) en die wordt geimplementeerd in zowel 'man' als 'vrouw'. Die is dan beschikbaar in een collection van het type 'person'.

ZO maak je OO modellen, niet middels Mien-uut-Ass'n geneuzel over 'een groep mensen is een groep persons en dus moeten alle eigenschappen die je wilt weten die in de man OF de vrouw zitten worden geplaatst in person'. Zo werkt het niet, want er is geen theoretische basis voor.
Helder verhaal EfBe.
Ik zal ff vertellen waar hun theoretische basis vandaan komt. Zij komen een beetje uit de tijd dat je programma's wiskundig ging zitten bewijzen (hee, wel met respect he ;)), dus wat hebben ze nou gedaan, ze hebben de wiskundige wetten van vereniging/verzameling erbij gehaald.

Hoe werkt dat? Als volgt: In real life is de verzameling mensen de vereniging van alle mannen en vrouwen, dus moet dat ook in het ontwerp terugkomen, i.e. alle verzamelde functionaliteit in bezit van Man en Woman vind je ook terug in Person, in andere woorden Person is de vereniging van Man en Woman. Toen ik dit hoorde ging zo'n beetje elke haar op m'n lijf recht overeind staan, want het gebruik van die wiskundige wet is gewoon hartstikke fout als je het over generalisatie/specialisatie hebt. D'r is geen match van die wet naar de programmeer wereld, het klopt niet, het kan niet, het mag niet, het is gewoon je reinste kolder. Echter, als ik als jong broekie aankom met 'het is onzin' of 'het mag niet', dan word ik uitgelachen 8)7

Wat ik graag zou zien is een of andere OO wet, die dit gewoon verbiedt. Iemand misschien ergens een boek of een weblink voor mij?

Verwijderd

Topicstarter
EfBe schreef op 07 June 2003 @ 19:15:
[...]

Allemaal leuk maar jij praat in de topicstart over inheritence, niet over aggregation. Als je person een aggregated object wilt maken, dan moet je dat doen, maar niet praten over inheritence, want dat heeft er niets mee te maken. COM is overigens niet OO, maar component oriented. Dat is wat anders, het ondersteunt nl. geen inheritence en polymorphism (al is dat laatste met vtable knoeiwerk wel te realiseren).

Aggregation komt nog zelden voor buiten de COM wereld, behalve in code waar proxy of adapter patterns worden gebruikt.
Ja je hebt gelijk, dat is juist het verschil dat ik probeerde aan te tonen, als mensen met voorbeelden komen van zus en zo is het geval, en ze halen daar een aggegratie voorbeeld bij, dan probeer ik duidelijk te maken dat ik het hier over inheritance heb.

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Dat vereniging verhaal is klassiek. Er is een thread over geweest hier op GoT, mbt oo model development, waarbij ik toen aangaf dat mensen oo niet begrijpen want je moet in is-a denken en dat doen mensen niet, mensen denken veelal aggregated. Ik zal ff struinen of ik die thread kan opsnorren, mbravenboer had daarin een goed verhaal erover.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Bingo: [rml][ DISC] Object Oriented development*[/rml]
(edit: dit is niet de goede thread. Ik zoek verder)

edit2: volgens mij bedoelde ik deze thread. Hij gaat over iets anders, maar het komt zeker aan bod: Backus over programmeertalen: actueel verleden

[ Voor 64% gewijzigd door EfBe op 07-06-2003 19:52 ]

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

Topicstarter
EfBe schreef op 07 June 2003 @ 19:28:
Dat vereniging verhaal is klassiek. Er is een thread over geweest hier op GoT, mbt oo model development, waarbij ik toen aangaf dat mensen oo niet begrijpen want je moet in is-a denken en dat doen mensen niet, mensen denken veelal aggregated. Ik zal ff struinen of ik die thread kan opsnorren, mbravenboer had daarin een goed verhaal erover.
Cool.
Dat aggregatie/inheritance verhaal is een beetje een zijspoor van deze discussie maar je hebt helemaal gelijk als je zegt dat mensen vaak de verschillen niet begrijpen. Maar ik ben wel benieuwd naar de thread. Wellicht brengt het hier verheldering.

Verwijderd

Topicstarter
EfBe schreef op 07 June 2003 @ 19:08:
... (downcasting in het algemeen is niet zo best). ...
Klopt. Maar is het niet zo dat je er niet onderuit komt als je met collections werkt. Als ik een collection van Persons heb, ik haal daar iemand uit, en van dit Person wil ik het geheim weten. Zal ik mezelf er dan niet eerst van moeten vergewissen dat het een Man is? Met andere woorden downcasten.
Als hier een betere manier voor is, dan hoor ik het uiteraard graag.

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op 07 June 2003 @ 19:57:
Klopt. Maar is het niet zo dat je er niet onderuit komt als je met collections werkt.
jawel, je moet collections maken om een reden, nl. dat je wilt werken met de eigenschappen van bv person. Dan maak je een collection van person objects en werkt dus met die eigenschappen. Wil je met de eigenschappen van 'man' werken, dan heb je NIETS aan zo'n person collectie, want daar zitten ook vrouwen tussen. Je moet dan dus een man collection maken.
Als ik een collection van Persons heb, ik haal daar iemand uit, en van dit Person wil ik het geheim weten. Zal ik mezelf er dan niet eerst van moeten vergewissen dat het een Man is? Met andere woorden downcasten.
Als hier een betere manier voor is, dan hoor ik het uiteraard graag.
Je moet dan downcasten, maar dat lukt niet bij een object van type 'vrouw'. M.a.w., als je met 'man' eigenschappen wilt werken en je gaat dan werken met een 'person' collection dan ben je niet handig bezig.

Downcasten kan nl. dan veel ellende geven, want je moet t.a.t je cast afvangen want een downcast naar man van een vrouw object geeft een exception. (of je moet kunnen testen dmv een taalconstruct). Ik doelde met die algemene term overigens op het algemene downcasten, dus van een person object een man object maken dmv een downcast, wat MFC nogal eens doet, en eigenlijk niet correct is.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
Verwijderd schreef op 07 June 2003 @ 19:57:
[...]
Zal ik mezelf er dan niet eerst van moeten vergewissen dat het een Man is? Met andere woorden downcasten.
zoiets noem ik toch upcasten hoor :) - ivm dat vergewisbaar: idd. en dat is ook steeds het probleem, je moet dus op de een of andere manier weten of je person een Man aldaniet Vrouw is. In Java is dit een poepie maar in C++ weet ik ook niet hoe je dit proper oplost. Meestal gebruik ik een GUID voor elk Type Object.

if (Person.getObjectID == GUID_MAN)
{
...
}

heb nooit geweten hoe je dit proper in C++ oplost

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:57
Verwijderd schreef op 07 June 2003 @ 18:34:
[...]


Volgens mij heb je het daar mis. Stel je voor dat ik een collectie van mensen wil hebben. Dan zal ik die collectie moeten declareren als een collectie van Persons.
Je zult de collectie inderdaad moeten definieren als een collectie van Persons.
Echter, ga je aan die persons echt wel Man of Woman gaan toewijzen. Dmv late-binding (polymorphing) wordt echter wel de juiste procedure uitgevoerd.

Maar verder ben ik er wel mee akkoord dat je die methods best in die specialisaties kan opnemen; het hang echter allemaal een beetje af van wat je er mee wil gaan doen.

[ Voor 15% gewijzigd door whoami op 07-06-2003 20:55 ]

https://fgheysels.github.io/


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

hobbit_be schreef op 07 juni 2003 @ 20:47:
In Java is dit een poepie maar in C++ weet ik ook niet hoe je dit proper oplost. Meestal gebruik ik een GUID voor elk Type Object.

if (Person.getObjectID == GUID_MAN)
{
...
}

heb nooit geweten hoe je dit proper in C++ oplost
Runtime typeinfo aanschakelen in de compiler (wil nog wel eens uitstaan bij sommige compilers als optimalisatie), en dynamic_cast gebruiken.
En zorgen dat de objecten een vtable hebben, maar dat is hier wel het geval :)

C++:
1
2
3
4
5
6
callGetSecretIfPersonIsMan (const Person & p)
{
    const Man * m = dynamic_cast<const Man *> (&p);
    if (m)
        m->getSecret ();
}

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Nappie
  • Registratie: September 2000
  • Laatst online: 03-11-2024

Nappie

Share and enjoy

Ha lekker,
Een leuk topic en ik heb nog het gevoel dat ik wat kan bijdragen ook :9~

Eerst maar het belangrijkste voor de discussie.
Waar je GetSecret() onderbrengt hangt af van je conceptuele model en van hoe je je klassen wil gebruiken. In een ideaal model slaag je er in om alleen eigenschappen van Persoon te gebruiken op de plaatsen waar je met Persoon referenties wil werken en dan kan je prima uit de voeten met een GetSecret() die niet in je base class zit. Typisch voorbeeld is dat je een paar routines hebt die op Personen werken en dat je daar Mannen en Vrouwen aan voert al naar gelang je daar zin in hebt.
In de praktijk gaat dat (bijna) nooit op voor je hele programma. Zoals hierboven ook al gezegd: zodra je je personen in 1 colection gaat opslaan heb je al problemen. Hoe je daarmee omgaat: dat hangt van de omstandigheden af. Per keer zal je moeten afwegen en in de praktijk kan je dat maar beter pragmatisch doen en niet al te puristisch. Met andere woorden: de ene keer ga je downcasten (yuk!), de andere keer zorg je voor een virtual in je base class die door een derived class wel of niet wordt overgedefinieerd. Soms zal je nog eens nadenken en je gaan afvragen of het voor deze toepassing wel zo logisch is om Vrouwen en Mannen van een gezamenlijk base class af te leiden.
Alternatief in dit geval: maak een class Man en een class Vrouw en bekijk een Persoon als iemand die mannelijke en/of vrouwelijke eigenschappen kan hebben: stop een Man of een Vrouw als data member in Persoon. Of dat wijs is hangt dus af van de rest van je programma.
Je kan er ook voor kiezen om niet te veranderen aan je class diagram, maar een Visitor (iemand dat wil, kan ik die ook nog wel uitleggen) te gebruiken wanneer je iets wil doen wat specifiek is voor een subclass. Dat laatste heb ik een paar keer gedaan en het werkt best aardig.
Om een lang verhaal kort te maken: jij en je collega's hebben allemaal gelijk (zoals altijd bij "heilige oorlogen").

edit:

Whoops, doe ik dus zo lang over typen dat een ander die dynamic_cast hieronder ook al heeft uitgelegd.


Even voor hobbit_be:
down casten in C++ doe je met een dynamic cast:
Persoon *p = new Man();
Persoon *q = new Vrouw();
Man *m = dynamic_cast<Man *>(p); // deze cast slaagt en m zal wijzen naar de Man.
m = dynamic_cast<Man *>(q); // deze cast faalt en m zal 0 worden.
if (m) {
cout<< "Man gevonden, geheim: " << m->secret();
} else {
cout << "Twas een vrouw";
}
Overigens MSVC6 zuigt hevig met dit soort spul.

Over links gesproken:
Handige link voor de C++er: http://users.utu.fi/sisasa/oasis/cppfaq/index.html
Als je voor je werk programmeert is het bijbehorende boek een *must*. Daar staat nog veel meer in. Onder andere een verhaal over "proper inheritance" en dat raakt aan dit topic. Proper inheritance is een manier om naar overerven te kijken die problemen voorkomt.

edit:

Faq 21 in de C++ faq light vertelt het verhaal hieronder ook al zie ik net.
http://users.utu.fi/sisas...q/proper-inheritance.html
Ofwel, hoe verspil tijd, les 1. 8)7


Ff kijken of ik dat nog een beetje uit mijn hoofd weet:
Als ik met geometrische figuren bezig ga, dan zou ik Elips van Cirkel af kunnen leiden. Een Elips kan ik zien als een Cirkel met een extra radius. Ik krijg dan wel het probleem (net als bij Persoon, Man en Vrouw) dat ik niet zo makkelijk bij die tweede radius kan komen als ik met Cirkels bezig ben. Dat kan ik oplossen door Cirkel ook een extra dummy-radius te geven, maar dan wordt mijn object-model nogal weird. Bovendien kan een gebruiker van Cirkel gebruik maken van het feit dat hoogte en breedte gelijk zijn bij een Cirkel. Dat probleem los ik niet zomaar op.

Ik kan het ook andersom proberen. Cirkel afleiden van Elips. Dan kan er echter weer wat fout gaan wanneer een gebruiker van een Elips er vanuit gaat dat ie de x en y radius allebei onafhankelijk van elkaar kan instellen.

Het komt er dus op neer dat je er bij inheritance gewoon heel zeker van moet zijn dat je subclass je base class echt alleen maar uitbreidt en dat er niet stiekem ook nog tegenstrijdige eigenschappen zijn in base en derived class. Het feit dat vanuit een bepaald standpunt de derived een uitbreiding is van de base doet er niet toe. Dit moet gelden binnen de context van je probleemdomein.

Zo, hoop dat dit helpt.

[ Voor 6% gewijzigd door Nappie op 07-06-2003 22:50 ]

Only way to feel the noise is when its good and loud.


  • whoami
  • Registratie: December 2000
  • Laatst online: 01:57
Nappie schreef op 07 June 2003 @ 22:41:

...je gaan afvragen of het voor deze toepassing wel zo logisch is om Vrouwen en Mannen van een gezamenlijk base class af te leiden.
offtopic:
The War of the Sexes
:Y)
Alternatief in dit geval: maak een class Man en een class Vrouw en bekijk een Persoon als iemand die mannelijke en/of vrouwelijke eigenschappen kan hebben: stop een Man of een Vrouw als data member in Persoon. Of dat wijs is hangt dus af van de rest van je programma.
Tja, dit kan je doen. Echter, ik denk dat het in deze context een beetje te ingewikkeld zal zijn. Is het niet beter als je het omgekeerd doet?
Dat je een class Man en een class Vrouw maakt, en deze niet laat overerven van Persoon maar dat deze een datamember hebben van het type Persoon ?
Uit jouw post maak ik op dat je het omgekeerd zou doen? Een class Persoon en dan ervoor zorgen dat die of een datatype Man of een datatype Vrouw heeft ?
Je kan er ook voor kiezen om niet te veranderen aan je class diagram, maar een Visitor (iemand dat wil, kan ik die ook nog wel uitleggen)
Alarmnummer heeft hier ooit al eens een tutorial over geschreven:
[rml][ alg] preview visitor artikel[/rml]

https://fgheysels.github.io/


  • Nappie
  • Registratie: September 2000
  • Laatst online: 03-11-2024

Nappie

Share and enjoy

Uit jouw post maak ik op dat je het omgekeerd zou doen? Een class Persoon en dan ervoor zorgen dat die of een datatype Man of een datatype Vrouw heeft ?
Dat is inderdaad wat meer vergezocht. Was vooral bedoeld om aan te geven dat er heel wat andere mogelijkheden zijn. Mijn punt is vooral: als je alleen dit class diagram hebt zonder context, dan kan je alle kanten uit. Er is dan zeker niet 1 beste oplossing.
Alarmnummer heeft hier ooit al eens een tutorial over geschreven:
Heb er even overheen gekeken en dat is precies wat ik bedoel. Ze zijn zeker niet ideaal, maar in bepaalde situaties een uitkomst.

Only way to feel the noise is when its good and loud.


  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
.oisyn schreef op 07 juni 2003 @ 22:10:
Runtime typeinfo aanschakelen in de compiler (wil nog wel eens uitstaan bij sommige compilers als optimalisatie), en dynamic_cast gebruiken.
En zorgen dat de objecten een vtable hebben, maar dat is hier wel het geval :)

C++:
1
2
3
4
5
6
callGetSecretIfPersonIsMan (const Person & p)
{
    const Man * m = dynamic_cast<const Man *> (&p);
    if (m)
        m->getSecret ();
}
hey en die m is NULL als de cast niet lukt dan? Dat wist ik niet! weer eens _/-\o_ dit is een 'openbaring' :)

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
Nappie schreef op 07 June 2003 @ 22:41:
Als ik met geometrische figuren bezig ga, dan zou ik Elips van Cirkel af kunnen leiden. Een Elips kan ik zien als een Cirkel met een extra radius. Ik krijg dan wel het probleem (net als bij Persoon, Man en Vrouw) dat ik niet zo makkelijk bij die tweede radius kan komen als ik met Cirkels bezig ben. Dat kan ik oplossen door Cirkel ook een extra dummy-radius te geven, maar dan wordt mijn object-model nogal weird. Bovendien kan een gebruiker van Cirkel gebruik maken van het feit dat hoogte en breedte gelijk zijn bij een Cirkel. Dat probleem los ik niet zomaar op.

Ik kan het ook andersom proberen. Cirkel afleiden van Elips. Dan kan er echter weer wat fout gaan wanneer een gebruiker van een Elips er vanuit gaat dat ie de x en y radius allebei onafhankelijk van elkaar kan instellen.
Ah, dat best een interessante situatie die je hier schetst. We hebben 'm hier op GoT al eens eerder besproken in het kader van OOP. Tot mijn schaamte kan ik me niet meer herinneren welk standpunt ik toen innam, maar volgens mij was ik het er juist niet mee eens dat een superklasse altijd moet 'uitbreiden' (in de zin van: meer attributen of methoden).

In plaats daarvan moet je kijken naar de mate van abstractie van het concept dat je modelleert: abstracte concepten (personen, vormen, etcetera) moeten hoog in de ervingsboom komen. Vanuit dat oogpunt is een cirkel een meer concrete vorm dan een ellips, dus hoort de cirkel af te leiden van de ellips. Elke cirkel is immers een soort ellips (met gelijke hoogte en breedte) maar niet elke ellips is een cirkel; analoog aan de constatering: elke man is een soort persoon, maar niet elk persoon is een man (wat wel direct logisch is).

Het probleem van Ash vind ik eigenlijk niet zo interessant: conceptueel hoort een attribuut van Man of Vrouw natuurlijk precies alleen daar thuis. Zo'n attribuut opnemen in Persoon is dan alleen vanuit praktische redenen te rechtvaardigen (maar zo'n concessie aan het OO-ontwerp is zelden terecht).

[ Voor 3% gewijzigd door Soultaker op 08-06-2003 11:09 ]


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Soultaker: over die elips idd dat was die thread die ik bedoelde hierboven!... darn, nog eens een zoekpoging doen.

edit: heh, geheugen doet rare dingen. Het ging over float / int derives. : oplossingen bij ambiguous function-sel. niet over cirkels en elipsen. Voor de topicstarter dus ook een leuke thread.

[ Voor 49% gewijzigd door EfBe op 08-06-2003 11:19 ]

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
EfBe schreef op 08 juni 2003 @ 11:16:
Soultaker: over die elips idd dat was die thread die ik bedoelde hierboven!... darn, nog eens een zoekpoging doen.
Mja, ik heb ook al gezocht op berichten van mezelf met 'cirkel' of 'ellips' erin, maar dat mocht niet baten.

edit:
Ah, EfBe heeft 'm ondertusen gevonden. Het ging inderdaad niet over cirkels/ellipsen (hoewel die wel genoemd zijn, dacht ik toch). Snel even m'n eigen reactie opgezocht en gelukkig: ik dacht er toen hetzelfde over (was ik anders even afgegaan :D).

[ Voor 32% gewijzigd door Soultaker op 08-06-2003 11:35 ]


Verwijderd

Topicstarter
EfBe schreef op 07 juni 2003 @ 20:45:
[...]

jawel, je moet collections maken om een reden, nl. dat je wilt werken met de eigenschappen van bv person. Dan maak je een collection van person objects en werkt dus met die eigenschappen. Wil je met de eigenschappen van 'man' werken, dan heb je NIETS aan zo'n person collectie, want daar zitten ook vrouwen tussen. Je moet dan dus een man collection maken.
Dat ben ik niet met je eens. Ik kan me heel goed voorstellen dat je in een situatie komt dat je een collection heb van een bepaald abstract datatype (bijv Person), en dat je dan van alle Man instanties een geheim wil weten. Ik zie er in dat geval helemaal geen probleem in om te downcasten nadat je je Person uit de collection hebt gehaald. Misschien is downcasten niet ideaal, maar kijk eens naar het alternatief. Het alternatief is absurd. Ik wil als baseclass Person echt niet weten wat mijn eventuele subclasses weten.
Je moet dan downcasten, maar dat lukt niet bij een object van type 'vrouw'. M.a.w., als je met 'man' eigenschappen wilt werken en je gaat dan werken met een 'person' collection dan ben je niet handig bezig.
Nee, en daarom zou ik zeggen, geef Person een vlaggetje 'sex', waarin je opgeeft wat iemands geslacht is. Tada, alle problemen opgelost.

Verwijderd

Topicstarter
Soultaker schreef op 08 juni 2003 @ 11:08:
[...]
Het probleem van Ash vind ik eigenlijk niet zo interessant: conceptueel hoort een attribuut van Man of Vrouw natuurlijk precies alleen daar thuis. Zo'n attribuut opnemen in Persoon is dan alleen vanuit praktische redenen te rechtvaardigen (maar zo'n concessie aan het OO-ontwerp is zelden terecht).
Je zegt 'zelden'. Kun je me dan een voorbeeld geven wanneer deze aanpak WEL terecht zou zijn. De consessie waar je het hier over hebt is het overboord gooien van alles wat met generalisatie/specialisatie te maken heeft, ten bate van...? Ten bate van wat?

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
Verwijderd schreef op 08 June 2003 @ 12:33:
Je zegt 'zelden'. Kun je me dan een voorbeeld geven wanneer deze aanpak WEL terecht zou zijn.
Ik kan me voorstellen dat je soms een situatie hebt waarin je een stuk of 10 afgeleide objecten hebt, waarvan er 9 wel zo'n attribuut hebben, en de 10e niet. Om te voorkomen dat je dan elke keer tussen 10 klassen onderscheid moet maken, zou je er dan ofwel voor kunnen kiezen om die 9 weer onder een aparte subklasse te zetten (wat netjes is, maar wel je ervingsboom weer dieper maakt) of je kunt dat attribuut in de superklasse te implementeren en die ene afwijkende klasse een default-waarde aan laten nemen.
De consessie waar je het hier over hebt is het overboord gooien van alles wat met generalisatie/specialisatie te maken heeft, ten bate van...? Ten bate van wat?
'Alles' is natuurlijk wat ver gezocht, maar als je weinig tijd hebt voor een nette implementatie, of je beschikt niet over RTTI, of performance is van het allergrootste belang (waardoor onderscheid maken niet wenselijk is), dan zou ik me kunnen voorstellen dat je zo'n concessie doet. Ten koste van het ontwerp en ten bate van het gemak of de prestaties van de implementatie.

Verwijderd

Topicstarter
Soultaker schreef op 08 June 2003 @ 13:13:
[...]

Ik kan me voorstellen dat je soms een situatie hebt waarin je een stuk of 10 afgeleide objecten hebt, waarvan er 9 wel zo'n attribuut hebben, en de 10e niet. Om te voorkomen dat je dan elke keer tussen 10 klassen onderscheid moet maken, zou je er dan ofwel voor kunnen kiezen om die 9 weer onder een aparte subklasse te zetten (wat netjes is, maar wel je ervingsboom weer dieper maakt) of je kunt dat attribuut in de superklasse te implementeren en die ene afwijkende klasse een default-waarde aan laten nemen.
Ok, en wat doe je dan in het geval van een collectie. Je hebt een item uit je collectie gehaald waarvan je alleen weet dat het een Person is, en iemand zegt GetSecret(). Nou is het zo dat 9 van je 10 subclasses een secret heeft (om jouw voorbeeld ff te volgen), welke van de 9 kies ik dan?
'Alles' is natuurlijk wat ver gezocht, maar als je weinig tijd hebt voor een nette implementatie, of je beschikt niet over RTTI, of performance is van het allergrootste belang (waardoor onderscheid maken niet wenselijk is), dan zou ik me kunnen voorstellen dat je zo'n concessie doet. Ten koste van het ontwerp en ten bate van het gemak of de prestaties van de implementatie.
Goed, akkoord, maar je bent dus wel met me eens dat het conceptueel brak is.

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Verwijderd schreef op 08 juni 2003 @ 13:21:
Ok, en wat doe je dan in het geval van een collectie. Je hebt een item uit je collectie gehaald waarvan je alleen weet dat het een Person is, en iemand zegt GetSecret(). Nou is het zo dat 9 van je 10 subclasses een secret heeft (om jouw voorbeeld ff te volgen), welke van de 9 kies ik dan?
Bij de extra subtree heb je dan maar 2 keuzes nodig en bij de superklasse-versie geen een. Maar in beide gevallen iig niet 9 of zelfs 10 opties.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op 08 juni 2003 @ 13:13:
[...]

Ik kan me voorstellen dat je soms een situatie hebt waarin je een stuk of 10 afgeleide objecten hebt, waarvan er 9 wel zo'n attribuut hebben, en de 10e niet. Om te voorkomen dat je dan elke keer tussen 10 klassen onderscheid moet maken, zou je er dan ofwel voor kunnen kiezen om die 9 weer onder een aparte subklasse te zetten (wat netjes is, maar wel je ervingsboom weer dieper maakt) of je kunt dat attribuut in de superklasse te implementeren en die ene afwijkende klasse een default-waarde aan laten nemen.
dat zou ik implementeren met een interface, waar je dan gewoon naar kunt querien of het geimplementeerd is met een instanceof constructie

Een javavoorbeeld (even zonder public enzo ;)):
Java:
1
2
3
4
5
6
7
8
9
10
11
interface HasSecret
{
    String GetSecret ();
}

class Man1 extends Person implements HasSecret
{
    // ...
}

// en definieer Man2 t/m Man9 net zo



En dan om te kijken of een Person een secret heeft dan doe je gewoon een person instanceof HasSecret, en vervolgens kun je er wat mee doen. Dat lijkt me een mooiere oplossing dan ervoor te kiezen dat per definitie elke persoon een secret heeft, en dan een default waarde teruggeven als dat niet het geval is.

Een andere mogelijkheid is natuurlijk door nog een class tussen de Person en de Mannen in te zetten, wat de verzameling personen met een geheim aangeeft. Dus PersonWithSecret extends Person, en Man1 t/m Man9 extends PersonWithSecret

Misschien ook een interessante discussie wat hier mooier is, een interface of de classtree aanvullen :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Classtree aanvulling is met een visitor-implementatie weer niet eens nodig, er zijn vrij veel opties iig :)

Verwijderd

Topicstarter
.oisyn schreef op 08 juni 2003 @ 13:34:
[...]


dat zou ik implementeren met een interface, waar je dan gewoon naar kunt querien of het geimplementeerd is met een instanceof constructie

Een javavoorbeeld (even zonder public enzo ;)):
Java:
1
2
3
4
5
6
7
8
9
10
11
interface HasSecret
{
    String GetSecret ();
}

class Man1 extends Person implements HasSecret
{
    // ...
}

// en definieer Man2 t/m Man9 net zo



En dan om te kijken of een Person een secret heeft dan doe je gewoon een person instanceof HasSecret, en vervolgens kun je er wat mee doen. Dat lijkt me een mooiere oplossing dan ervoor te kiezen dat per definitie elke persoon een secret heeft, en dan een default waarde teruggeven als dat niet het geval is.

Een andere mogelijkheid is natuurlijk door nog een class tussen de Person en de Mannen in te zetten, wat de verzameling personen met een geheim aangeeft. Dus PersonWithSecret extends Person, en Man1 t/m Man9 extends PersonWithSecret

Misschien ook een interessante discussie wat hier mooier is, een interface of de classtree aanvullen :)
Jaja, je hebt helemaal gelijk, maar interfaces kan ik in onze discussie niet gebruiken want de heren weten niet wat dat zijn :P
En daarbij interfaces werken natuurlijk alleen maar als je als baseclass ECHT abstract bent, dus nul functionaliteit hebt, hetgeen niet altijd het geval is.
Maar in dit specifieke geval heb je gelijk.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
.oisyn schreef op 08 June 2003 @ 13:34:
dat zou ik implementeren met een interface, waar je dan gewoon naar kunt querien of het geimplementeerd is met een instanceof constructie
Dat is inderdaad nog een mooiere oplossing. Het moge duidelijk zijn dat ik uitsluitend bedoelde dat het voor kan komen; niet dat het in het algemeen een goede oplossing is.

Jouw voorstel gaat bijvoorbeeld weer niet op als je geen RTTI hebt; dan moet je een andere constructie (op basis van 'n Visitor pattern of iets dergelijks) verzinnen om je gedrag specifiek aan het object te koppelen. (In het geval van een Visitor betekent het dan eigenlijk dat je Person een hasSecret methode krijgt!)
Een andere mogelijkheid is natuurlijk door nog een class tussen de Person en de Mannen in te zetten, wat de verzameling personen met een geheim aangeeft. Dus PersonWithSecret extends Person, en Man1 t/m Man9 extends PersonWithSecret
Inderdaad, die mogelijkheid was ook genoemd. In het algemeen vind ik het zelf prettig om de klassestructuur een beetje plat te houden (is overzichterlijker). Uiteraard moet het argument om wel of niet een extra klasse tussen te voegen luiden dat die extra klasse een abstractie van al zijn subklassen is; als de subklassen toevallig eenzelfde attribuut hebben maar verder conceptueel geen relatie hebben, dan zou ik liever ofwel die interface gebruiken, ofwel allemaal een eigen attribuut geven.
Misschien ook een interessante discussie wat hier mooier is, een interface of de classtree aanvullen :)
Een interface, lijkt mij, mits die een eigenschap aanduidt die onafhankelijk is van de verdere ervingsboom (dus wanneer elke klasse min of meer willekeurig wel of niet die interface zou kunnen ondersteunen).

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Mja ik denk dat RTTI in z'n lichtste vorm, dus gewoon controleren of een type ook een ander type is, toch een essentieel OO eigenschap is. Er zijn gewoon situaties waarbij je moet casten naar een specifieker type (heet dat nou down- of upcasten?), en dan is het eigenlijk wel van belang dat je ook kan controleren dat het een dergelijk type is.

Verder is het nadeel van een interface weer wel dat je het in de meeste talen (zo niet alle) niet als verplichting kunt opgeven als functieargument. Als een functie namelijk een Person met een secret verwacht, dan is er geen mogelijkheid om dat @ compiletime op te dwingen. Het zou mooi zijn als dit werkte:
Java:
1
2
3
4
5
6
void functie (Person implements HasSecret p)
{
}

Woman bla = new Woman ();
functie (bla); // compile-error: Woman heeft geen secret


Dit is op te lossen door een PersonWithSecret te defineren. Maar ja, dan zit je weer in je classtree te kloten, wat imho ook niet helemaal goed is. Overigens lost bovenstaand stukje code ook niet alle errors @ compiletime op. Want als de caller gewoon een Person heeft is dus niet @ compiletime bekend of ie ook daadwerkelijk HasSecret implementeerd, waardoor de runtime check dus alsnog nodig is

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

.oisyn schreef op 08 juni 2003 @ 13:54:
Verder is het nadeel van een interface weer wel dat je het in de meeste talen (zo niet alle) niet als verplichting kunt opgeven als functieargument. Als een functie namelijk een Person met een secret verwacht, dan is er geen mogelijkheid om dat @ compiletime op te dwingen.
Als je dat al weet, tijdens compileren en je hebt ook nog eens die interface, waarom doe je dan niet:
Java:
1
2
3
4
5
6
void functie (HasSecret p)
{
}

Woman bla = new Woman ();
functie (bla); // compile-error: Woman heeft geen secret


Of bedoel je dat Java/whichever zou moeten checken of de klasse voldoet aan een Interface, zonder dat jij dat zo gespecificeerd hebt?

Wat als er twee interfaces zijn die dezelfde methoden definieren (wat niet perse fout is, maar doorgaans niet handig :) ) en het meegegeven object was eigenlijk bedoeld om te voldoen aan de tweede interface, terwijl jij opgaf dat ie aan de eerste moest voldoen...

In dat geval krijg je geen compile-error terwijl je dat wel moest krijgen...

Lama, ik snap al wat je bedoeld :)

Je wil dat er gechecked wordt of het een Person is én een die dan HasSecret implementeert.

[ Voor 6% gewijzigd door ACM op 08-06-2003 14:02 ]


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op 08 juni 2003 @ 12:26:
Dat ben ik niet met je eens. Ik kan me heel goed voorstellen dat je in een situatie komt dat je een collection heb van een bepaald abstract datatype (bijv Person), en dat je dan van alle Man instanties een geheim wil weten. Ik zie er in dat geval helemaal geen probleem in om te downcasten nadat je je Person uit de collection hebt gehaald. Misschien is downcasten niet ideaal, maar kijk eens naar het alternatief. Het alternatief is absurd. Ik wil als baseclass Person echt niet weten wat mijn eventuele subclasses weten.
Het is broddelen. Als jij met de class 'man' wilt werken, leg je OOK een collectie van 'man' aan en gaat daarmee werken. Is veel efficienter, want je komt geen type 'vrouw' tegen.
[...]
Nee, en daarom zou ik zeggen, geef Person een vlaggetje 'sex', waarin je opgeeft wat iemands geslacht is. Tada, alle problemen opgelost.
Dat is toch logisch? "geslacht" is een eigenschap van person, dus plaats je dat bij het type person, zoals ik zei hierboven.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • EfBe
  • Registratie: Januari 2000
  • Niet online
.oisyn schreef op 08 June 2003 @ 13:34:
[...]
dat zou ik implementeren met een interface, waar je dan gewoon naar kunt querien of het geimplementeerd is met een instanceof constructie
Ja duh, dat is hetzelfde als testen of het object van het type 'man' is. :) Als je eerst generaliseert dmv een collectie over het type 'person' en daarna wil je weer specialiseren met diezelfde abstractere types, dan lukt je dat alleen door elke keer te testen, wat knoeiwerk is. Je maakt OF een collectie van persons want je wilt werken met dat type person, OF je maakt 2 collecties, mannen en vrouwen, en gaat met beide afzonderlijk werken als je specifieke eigenschappen wilt weten van een bepaald type. Die collecties, mannen en vrouwen, kunnen referenties bevatten naar dezelfde objects waar persons ook referenties naar heeft.

Het gaat om het besef wat een type is, waarom eigenschappen van dat type juist bij dat type worden geplaatst en waarom andere eigenschappen NIET, plus dat een instance meerdere typen kan hebben, maar dat je dat niet WEET bij voorbaat.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

EfBe schreef op 08 June 2003 @ 14:10:
Ja duh, dat is hetzelfde als testen of het object van het type 'man' is. :)
Uhm, SoulTaker kwam met het geval dat er 9 verschillende typen waren die een secret hadden, en 1 niet.

En in plaats van gewoon de superclasse een methode GetSecret () te geven en dat ene geval een default waarde terug te geven, is het beter om een interface te maken, zodat je maar 1 check uit hoeft te voeren. Ja, bij Man/Vrouw zijn er maar 2 types, maar daar ging het hier niet om

Of vind jij het handig dat je 9 verschillende checks doet? :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
EfBe schreef op 08 June 2003 @ 14:05:
[...]

Het is broddelen. Als jij met de class 'man' wilt werken, leg je OOK een collectie van 'man' aan en gaat daarmee werken. Is veel efficienter, want je komt geen type 'vrouw' tegen.
Het is geen broddelen, ik heb een collection Persons en wil alleen van de Mannen daarin iets weten. Dit is een heel normaal en veel voorkomend voorbeeld. Een collection van alleen Mannen werkt alleen als ik zeker weet dat ik geen vrouwen tegenkom, maar als dat niet zo is, dan is dat gewoon niet zo.
Ik maak bij die collection juist gebruik van hun gemeenschappelijkheden, namelijk het feit dat ze Person zijn. Dit is normaal omgaan met OO en helemaal nix mis mee. Als jij downcasten broddelen vindt, kom dan met een alternatief.
Dat is toch logisch? "geslacht" is een eigenschap van person, dus plaats je dat bij het type person, zoals ik zei hierboven.
Mee eens, en en als je dan een instantie van Person hebt (waar je soms niet omheen kunt, zie bovenstaand voorbeeld), vraag je z'n 'geslacht' op, is die 'Man', prima, secret opvragen. Is het geen Man, doe je gewoon niets. Naar mijn mening is dit de enige nette manier om hiermee om te gaan.

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op 08 juni 2003 @ 13:41:
Jaja, je hebt helemaal gelijk, maar interfaces kan ik in onze discussie niet gebruiken want de heren weten niet wat dat zijn :P
En daarbij interfaces werken natuurlijk alleen maar als je als baseclass ECHT abstract bent, dus nul functionaliteit hebt, hetgeen niet altijd het geval is.
Maar in dit specifieke geval heb je gelijk.
huh? Interfaces zijn gewoon type definities. Ik kan dit definieren:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface IPersoon
{
    string Naam {get; set;}
    short Leeftijd {get; set;}
    Geslachten Geslacht {get; set;}
}

public interface IMan: IPersoon
{
    string Geheim {get; set;}
}

public interface IVrouw: IPersoon
{
    byte AantalKinderen {get; set;}
}

en dan heb ik 3 typen gedefinieerd. Ik kan ook de interface IMan los van 'persoon' definieren, maar dan heb ik wanneer ik met IMan instances werk geen IPersoon eigenschappen tot mijn beschikking.

Zie je dat ik geen reet over implementatie zeg? Als ik doe:
IMan sjaak = new Man();
dan heeft sjaak de IMan EN de IPersoon interface, dus die typen. Je collega's snappen niet wat interfaces zijn aldus jou, maar je hebt er zelf ook nog wat moeite mee ;)

Verder, als men dit soort basisbegrippen niet kent, dan is OO development een hell, en dit soort discussies vrij zinloos.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • EfBe
  • Registratie: Januari 2000
  • Niet online
.oisyn schreef op 08 June 2003 @ 14:14:
Uhm, SoulTaker kwam met het geval dat er 9 verschillende typen waren die een secret hadden, en 1 niet.
En in plaats van gewoon de superclasse een methode GetSecret () te geven en dat ene geval een default waarde terug te geven, is het beter om een interface te maken, zodat je maar 1 check uit hoeft te voeren. Ja, bij Man/Vrouw zijn er maar 2 types, maar daar ging het hier niet om
Of vind jij het handig dat je 9 verschillende checks doet? :)
Nee, maar ik definieer 'GetSecret()' bij het type waar dat concept bekend is, dus als dat het supertype is, dan definieer ik het daar. Is dat niet zo, dan definieer ik het een laag lager. Dus inderdaad, als je 10 subtypes hebt, waarvan 1 het concept secret niet kent, dan kan het supertype dat sowieso niet kennen en zul je inderdaad een common type moeten definieren voor die 9 waar getsecret in wordt gedefinieerd.

Ik begreep je posting in het kader van het werken met objects van het person type terwijl je de 'man' objects wilt hebben, wat naar nu blijkt niet correct was :)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op 08 June 2003 @ 14:14:
Het is geen broddelen, ik heb een collection Persons en wil alleen van de Mannen daarin iets weten. Dit is een heel normaal en veel voorkomend voorbeeld. Een collection van alleen Mannen werkt alleen als ik zeker weet dat ik geen vrouwen tegenkom, maar als dat niet zo is, dan is dat gewoon niet zo.
Ik maak bij die collection juist gebruik van hun gemeenschappelijkheden, namelijk het feit dat ze Person zijn. Dit is normaal omgaan met OO en helemaal nix mis mee. Als jij downcasten broddelen vindt, kom dan met een alternatief.
Nee, je snapt niet wat ik bedoel. Als je met het type 'man' wilt werken, moet je met een collection met objects van dat type werken en niet met een collection met objects van het type 'person', want dan moet je elk object bekijken en casten en testen en dat is mateloos inefficient, want stel dat er 2 mannen en 2000 vrouwen in die collection zitten. Lekkere broddelcode.

Als jij alle objects van het type 'man' wilt gebruiken in een algorithme, dan moet je die collection pakken en dan het algoritme daarop loslaten. Het algoritme moet er vanuit gaan dat wat als input dient niet van het type 'aap' of 'huis' is maar 'man'.

Je zegt dat je met de 'person' collection gebruik maakt van hun gemeenschappelijkheden, nou dat is heel goed. Maar als je bezig bent op specialistisch niveau, nl. iets dat gerelateerd is aan een subtype van person, dan zit je met een collection van 'person' volledig fout: jij kachelt alle objects langs om te kijken of ze man zijn. Met een collection van 20.000 persons en 10 mannen is dat lekker inefficiente boutcode, pardon my french. Wat je nl. wilt is een view op de totale collection persons die louter een subtype van persons toont, nl 'man-collection'. Deze collection refereert naar objects die ook in de 'person' collection voorkomen. Echter je kunt dan WEL meteen werken met een efficient algoritme, want je hoeft niet eerst 20.000 objects te checken en te casten, je kunt meteen 10 objects langs en klaar ben je.

DAT Is efficiente code, niet dat gebroddel van 'ik heb hier een collection met het supertype, ik zoek gewoon de objects op van het subtype', want dan begrijp je de kracht van types niet.
[...]
Mee eens, en en als je dan een instantie van Person hebt (waar je soms niet omheen kunt, zie bovenstaand voorbeeld), vraag je z'n 'geslacht' op, is die 'Man', prima, secret opvragen. Is het geen Man, doe je gewoon niets. Naar mijn mening is dit de enige nette manier om hiermee om te gaan.
Nee. want 'man' kan wel weer geinherit worden door een ander subtype en je wilt dan naar DIE zn eigenschappen vragen, ga je dan 2 keer testen? Wordt een lekkere kerstboom van if then else zus en zo code. Maar goed, het is jouw code natuurlijk, laat je toch vooral niet tegenhouden in het bouwen van efficiente programmatuur :)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

Topicstarter
EfBe schreef op 08 June 2003 @ 14:16:
[...]


Zie je dat ik geen reet over implementatie zeg? Als ik doe:
IMan sjaak = new Man();
dan heeft sjaak de IMan EN de IPersoon interface, dus die typen. Je collega's snappen niet wat interfaces zijn aldus jou, maar je hebt er zelf ook nog wat moeite mee ;)

Verder, als men dit soort basisbegrippen niet kent, dan is OO development een hell, en dit soort discussies vrij zinloos.
Dat laatste ben ik met je eens, maar waaruit haal je dat ik niet weet wat een interface is. Ik heb gezegd dat een interface geen functionaliteit mag hebben, meer niet. En een ECHTE interface heb je alleen in Java, en C++ vertaalt zich dat naar classes met pure virtuals. Het probleem is dat als je over interfaces praat, al heel implementatie gericht bezig bent.
Wat ik wil is, los van wat je nou precies gebruikt als base class (interface, pure virtual dingen, of wat dan ook), dat het conceptueel fout is kennis/functionaliteit in je baseclass te stoppen die specifiek is voor 1 of meer (maar niet alle) van zijn subclasses. Als we het daar over eens worden, kunnen we het implementatie-technische gebabbel achterwege laten :)

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

EfBe schreef op 08 June 2003 @ 14:29:
Wat je nl. wilt is een view op de totale collection persons die louter een subtype van persons toont, nl 'man-collection'. Deze collection refereert naar objects die ook in de 'person' collection voorkomen. Echter je kunt dan WEL meteen werken met een efficient algoritme, want je hoeft niet eerst 20.000 objects te checken en te casten, je kunt meteen 10 objects langs en klaar ben je.

DAT Is efficiente code, niet dat gebroddel van 'ik heb hier een collection met het supertype, ik zoek gewoon de objects op van het subtype', want dan begrijp je de kracht van types niet.
Maar op het moment dat je alleen die collectie van personen hebt, dan zul je toch op dezelfde inefficiente manier je man-collectie moeten aanmaken... Of wilde je dan in je collectie al speciale views gaan lopen bijhouden tijdens het 'inserten' in je collectie?

Afhankelijk van de toepassing is het maar de vraag of dat wel efficienter is dan domweg af en toe inefficient door _al_ je objecten te lopen. ('t wordt helemaal spannend als het dynamische type van een object in je collection veranderd, dat kan je collection echt niet zomaar afvangen)

Ik blijf iig bij de stelling dat het gewoon afhangt van de toepassing wat het beste is, maar dat als er een "toepassingsloze vraag" gesteld wordt er naar de ontwerptechnisch beste keus (en dat zal wel een apart subtype zijn en de zaken daar te definieren waar ze ook daadwerkelijk zitten, zijn oid) :)

[ Voor 5% gewijzigd door ACM op 08-06-2003 14:35 ]


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Wat ik wil is, los van wat je nou precies gebruikt als base class (interface, pure virtual dingen, of wat dan ook), dat het conceptueel fout is kennis/functionaliteit in je baseclass te stoppen die specifiek is voor 1 of meer (maar niet alle) van zijn subclasses. Als we het daar over eens worden, kunnen we het implementatie-technische gebabbel achterwege laten
Een class is 1) zijn eigen type en 2) elk type van de base class en 3) elk type van de geimplementeerde interfaces. Als jij iets plaatst in een base class dan heeft dat betrekking op dat type en elke inheritor heeft dus ook dat type. Als jij penislengte opneemt in de class 'person' dan heeft de inheritor 'vrouw' dat type dus ook, dus ook het attribute 'penislengte'. Aangezien penislengte niet een eigenschap is van 'person' als type, kun je dat daar niet plaatsen, maar zul je dat ergens anders moeten plaatsen, nl. in het type waar het wel betrekking op heeft. Dat is PRECIES wat het concept 'type' inhoudt.

Interfaces zijn dus type definities, geen implementatie-gerichte onzin.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

Topicstarter
EfBe schreef op 08 June 2003 @ 14:29:
[...]

Nee, je snapt niet wat ik bedoel. Als je met het type 'man' wilt werken, moet je met een collection met objects van dat type werken en niet met een collection met objects van het type 'person', want dan moet je elk object bekijken en casten en testen en dat is mateloos inefficient, want stel dat er 2 mannen en 2000 vrouwen in die collection zitten. Lekkere broddelcode.

Als jij alle objects van het type 'man' wilt gebruiken in een algorithme, dan moet je die collection pakken en dan het algoritme daarop loslaten. Het algoritme moet er vanuit gaan dat wat als input dient niet van het type 'aap' of 'huis' is maar 'man'.

Je zegt dat je met de 'person' collection gebruik maakt van hun gemeenschappelijkheden, nou dat is heel goed. Maar als je bezig bent op specialistisch niveau, nl. iets dat gerelateerd is aan een subtype van person, dan zit je met een collection van 'person' volledig fout: jij kachelt alle objects langs om te kijken of ze man zijn. Met een collection van 20.000 persons en 10 mannen is dat lekker inefficiente boutcode, pardon my french. Wat je nl. wilt is een view op de totale collection persons die louter een subtype van persons toont, nl 'man-collection'. Deze collection refereert naar objects die ook in de 'person' collection voorkomen. Echter je kunt dan WEL meteen werken met een efficient algoritme, want je hoeft niet eerst 20.000 objects te checken en te casten, je kunt meteen 10 objects langs en klaar ben je.

DAT Is efficiente code, niet dat gebroddel van 'ik heb hier een collection met het supertype, ik zoek gewoon de objects op van het subtype', want dan begrijp je de kracht van types niet.

[...]

Nee. want 'man' kan wel weer geinherit worden door een ander subtype en je wilt dan naar DIE zn eigenschappen vragen, ga je dan 2 keer testen? Wordt een lekkere kerstboom van if then else zus en zo code. Maar goed, het is jouw code natuurlijk, laat je toch vooral niet tegenhouden in het bouwen van efficiente programmatuur :)
Ja maar jongen, die 'view' waar je het over hebt, hoe maak ik die dan. Ga ik mijn collectie van 2000 mensen pakken, daar de 10 Mannen uithalen, die in een nieuwe collectie stoppen, en vervolgens 'super efficient' die 10 Mannen querien voor hun secret. Hoe is dat efficienter? Je zult ze toch allemaal af moeten :P

En over die subtypes: Al heb je 80.000 subtypes, zodra ik als 'buitenstaander' zeg maar, een object heb van type Person en ik moet 1 van de 80.000 subtypes hebben (laten we zeggen ManMetHoedEnSnorEn2LabradorsEnOpelKadet), dan cast ik hem gewoon rechtstreeks naar ManMetHoedEnSnorEn2LabradorsEnOpelKadet, klaar. Zou ik die GetSecret() nou in Person laten staan, moet ik in GetSecret() een of ander case statement hebben staan met 80.000 entries, immers, iemand zou wel eens GetSecret() op mij kunnen aanroepen voor subtype ManMetHoedEnSnorEn2LabradorsEnOpelKadet.
Snappie?

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Ash: zou je trouwens, om de lengte van de thread wat in te perken, willen proberen de quotes gericht te doen. Dus als je op de hele reactie reageert, de hele reactie weghalen en enkel het "Blabla zei...." te laten staan of een korte samenvattende zin en als je op een specifiek deel reageert dat specifieke deel te quoten? :)

't Zijn al van die lange posts, dat erbij maakt het alleen nog maar langer :)

[ Voor 4% gewijzigd door ACM op 08-06-2003 14:42 ]


Verwijderd

Topicstarter
EfBe schreef op 08 June 2003 @ 14:34:
[...]

Een class is 1) zijn eigen type en 2) elk type van de base class en 3) elk type van de geimplementeerde interfaces. Als jij iets plaatst in een base class dan heeft dat betrekking op dat type en elke inheritor heeft dus ook dat type. Als jij penislengte opneemt in de class 'person' dan heeft de inheritor 'vrouw' dat type dus ook, dus ook het attribute 'penislengte'. Aangezien penislengte niet een eigenschap is van 'person' als type, kun je dat daar niet plaatsen, maar zul je dat ergens anders moeten plaatsen, nl. in het type waar het wel betrekking op heeft. Dat is PRECIES wat het concept 'type' inhoudt.

Interfaces zijn dus type definities, geen implementatie-gerichte onzin.
Ok, maar dan kun je het dus alleen maar met mijn eens zijn met betrekking tot mijn GetSecret() verhaal, waar het allemaal om begonnen was. secret is geen eigenschap van ALLE Persons, derhalve hoort ie niet in Person thuis.
Ja toch?

  • EfBe
  • Registratie: Januari 2000
  • Niet online
ACM schreef op 08 juni 2003 @ 14:34:
Maar op het moment dat je alleen die collectie van personen hebt, dan zul je toch op dezelfde inefficiente manier je man-collectie moeten aanmaken... Of wilde je dan in je collectie al speciale views gaan lopen bijhouden tijdens het 'inserten' in je collectie?
Fout uitgangspunt. Je moet niet uitgaan van 'maar stel dat je maar een collection 'person' objects hebt, je moet uitgaan van algoritmen: wat moet ik doen, heb ik aan een generieke collection genoeg of heb ik iets meer getypeerder nodig? Indien ja, dan bouw je dat, nl wanneer je instances maakt van 'man' en 'vrouw', dus op de lowest leaf.
Afhankelijk van de toepassing is het maar de vraag of dat wel efficienter is dan domweg af en toe inefficient door _al_ je objecten te lopen.
Kom op, ACM... :) je maakt t.a.t. 1 keer een instance van man of vrouw. Person instances zijn sowieso waardeloos mbt 'man' of 'vrouw', want die kun je NOOIT downcasten, en terecht. Jij maakt een instance aan van 'man' en je plaatst hem in 2 collections ipv in 1. En jij gaat nu beweren dat het plaatsen van 'man' in 2 collections 'duurder' is dan het afsjouwen van die ene collection met allerlei tests? Alleen in het geval van 2 objects.
Ik blijf iig bij de stelling dat het gewoon afhangt van de toepassing wat het beste is, maar dat als er een "toepassingsloze vraag" gesteld wordt er naar de ontwerptechnisch beste keus (en dat zal wel een apart subtype zijn en de zaken daar te definieren waar ze ook daadwerkelijk zitten, zijn oid) :)
Nee, algoritmes, niet implementatie. Lees mn blog van vandaag maar door. :) Je moet t.a.t. kunnen aantonen dat je algoritme van een zekere orde is en dus efficienter dan een ander algoritme van een andere orde. Je maakt mij niet wijs dat dom objects langskachelen en dan ieder object testen (en wellicht vaker testen als je naar specifieke vrouwen zoekt, dus subtype van 'vrouw') effienter is als algoritme dan specifiek een collection van objects van dat type langskachelen: je doorzoekt ten eerste t.a.t. (in het laatste geval) geen 1 object te veel en ten tweede spaar je (wellicht dure) tests uit. Kom je tijdens een implementatie er achter dat je een subcollection nodig hebt, dan moet je die aanmaken op de meest efficiente manier, nl. wanneer je de objects creeert, want DAN weet je wat het type is zonder te testen.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op 08 June 2003 @ 14:41:
Ok, maar dan kun je het dus alleen maar met mijn eens zijn met betrekking tot mijn GetSecret() verhaal, waar het allemaal om begonnen was. secret is geen eigenschap van ALLE Persons, derhalve hoort ie niet in Person thuis.
Ja toch?
JA. En je moet er ook niet naar refereren als je met persons werkt. Je moet dus OOK niet gaan broddelen en proberen ieder person object te laten veranderen in een man en dan kijken of het lukt. "Hey, het lukt niet, jij bent zeker vrouw he?" "ja". "dacht ik al. Volgende!". Dat is prutsen, knoeien, broddelen. :)

En hoe je die collections aanmaakt? Nou wat dacht je van wanneer je de objects zelf aanmaakt? Of maak jij man en vrouw objects aan en dumpt ze in een person collection en gaat dan alle man OF vrouw acties via die person collection doen? Aandelen AMD/Intel gekocht? :)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

EfBe schreef op 08 June 2003 @ 14:43:
Fout uitgangspunt. Je moet niet uitgaan van 'maar stel dat je maar een collection 'person' objects hebt, je moet uitgaan van algoritmen: wat moet ik doen, heb ik aan een generieke collection genoeg of heb ik iets meer getypeerder nodig? Indien ja, dan bouw je dat, nl wanneer je instances maakt van 'man' en 'vrouw', dus op de lowest leaf.
Ik snap wat je bedoeld, maar op het moment dat er 100 verschillende typen zijn en je er op verschillende niveau's mee moet werken, is het bijhouden van 100 losse collections (en nog een X aantal collections voor de "tussenstap typen") niet heel mooi of handig. Je zult dan niet heel gauw algoritmes op 1 van de 100 loslaten, maar toch.
Kom op, ACM... :) je maakt t.a.t. 1 keer een instance van man of vrouw. Person instances zijn sowieso waardeloos mbt 'man' of 'vrouw', want die kun je NOOIT downcasten, en terecht. Jij maakt een instance aan van 'man' en je plaatst hem in 2 collections ipv in 1. En jij gaat nu beweren dat het plaatsen van 'man' in 2 collections 'duurder' is dan het afsjouwen van die ene collection met allerlei tests? Alleen in het geval van 2 objects.
Nou zullen mannen en vrouwen niet gauw van type veranderen tijdens het proces (hoewel het niet perse onmogelijk is) maar op het moment dat dat wel mogelijk is in je applicatie heb je met die aanpak een groot probleem.
Want dan zou je vrouwen in je man-collectie en mannen in je vrouw-collectie krijgen, terwijl je de type verandering niet of nauwelijks kunt achterhalen vanuit je collections gezien (die pogen een strikte scheiding te houden).

Op zo'n moment lijkt mij niet dat je gescheiden collections beter zijn in efficientie dan een grote... Je moet alsnog elk type controleren en de andere collecties ook doorlopen.
En wellicht ben je dan ook niet helemaal handig bezig, want het zou idd handig kunnen zijn dat op het moment dat je een object van type veranderd dat je hem ook gelijk maar in een andere collectie stopt... Maar is dat altijd gewenst of mooi?
Nee, algoritmes, niet implementatie.
Wat jij met algortimes aanduidt is wat ik met toepassingen bedoel, hoewel ik wel de term ruimer bedoel, dus ook het invoeren van je objecten en alle algoritmes samen.
Je maakt mij niet wijs dat dom objects langskachelen en dan ieder object testen (en wellicht vaker testen als je naar specifieke vrouwen zoekt, dus subtype van 'vrouw') effienter is als algoritme dan specifiek een collection van objects van dat type langskachelen: je doorzoekt ten eerste t.a.t. (in het laatste geval) geen 1 object te veel en ten tweede spaar je (wellicht dure) tests uit.
Nee dat wil ik je niet wijs maken want je hebt daar helemaal gelijk in :)
Kom je tijdens een implementatie er achter dat je een subcollection nodig hebt, dan moet je die aanmaken op de meest efficiente manier, nl. wanneer je de objects creeert, want DAN weet je wat het type is zonder te testen.
Ik beweer alleen dat je niet altijd een subcollection _kan_ aanmaken en dat het dus ook niet altijd de meest efficiente manier is om de subcollection te proberen bij te houden :)

Owja, en soms is het, imho, ook niet nodig zoiets aan te maken. Als je in je hele applicatie-executie maar een marginaal aantal keren de hele collectie "foutief" doorloopt en verder vrijwel altijd wel de hele collectie moet hebben is het onzin er een aparte subcollectie voor bij te houden, het kost alleen maar weer extra programmeertijd om dat allemaal en overal netjes bij te houden :)

[ Voor 6% gewijzigd door ACM op 08-06-2003 14:57 ]


Verwijderd

Topicstarter
EfBe schreef op 08 June 2003 @ 14:46:
[...]

JA. En je moet er ook niet naar refereren als je met persons werkt. Je moet dus OOK niet gaan broddelen en proberen ieder person object te laten veranderen in een man en dan kijken of het lukt. "Hey, het lukt niet, jij bent zeker vrouw he?" "ja". "dacht ik al. Volgende!". Dat is prutsen, knoeien, broddelen. :)
Je hebt gelijk als ik van te voren zou weten dat elke Person een Man zou zijn, en in dit voorbeeld doe ik ook alleen maar iets met de Man, namelijk secret opvragen. Dan kun je je inderdaad afvragen waarom je geen collection van alleen Man aanmaakt. Maarrrr, misschien dient die collectie wel een ander globaler doel binnen de applicatie.

Ik vind het helemaal niet raar dat bijvoorbeeld een ziekenhuis een datastructuur van Patienten heeft, met subtypes Man, Vrouw, en wie weet wat voor subtypes nog meer. Ik vind het dan ook niet raar, dat je dan zon Patient pakt en hem downcast naar dat ding waar je mee wil werken, bijvoorbeeld Man. In jouw geval moet het ziekenhuis allemaal aparte collections gaan bijhouden van elk subtype van Patient, want jij wil er efficient over kunnen itereren.

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Wat trouwens wel mooi zou zijn, imho, is in zo'n geval een eigen collection-class te implementeren die in eerste instantie gewoon de "luie aanpak" volgt, maar wel gelijk al losse iterators aanbiedt.
Dus een ManIterator en een VrouwIterator, etc. En evt ook gelijk al een addMan(), addVrouw, etc.

Op het moment dat dan blijkt dat de boel echt efficienter moet kan je dan heel simpel, zonder de rest van je applicatie te slopen (dus niet 'at creationtime' de boel al aanpassen), losse collections gaan bijhouden :)

Echter blijf ik er dus bij dat het van je toepassing afhangt of dat allemaal nodig is :P

Verwijderd

Topicstarter
ACM schreef op 08 June 2003 @ 15:03:
Wat trouwens wel mooi zou zijn, imho, is in zo'n geval een eigen collection-class te implementeren die in eerste instantie gewoon de "luie aanpak" volgt, maar wel gelijk al losse iterators aanbiedt.
Dus een ManIterator en een VrouwIterator, etc. En evt ook gelijk al een addMan(), addVrouw, etc.
Mja STL heeft daar iets voor d8 ik. for_each kun je ook per type doen als ik me niet vergis, maar dat is ff te lang geleden voor me :P

[ Voor 25% gewijzigd door Verwijderd op 08-06-2003 15:08 ]


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op 08 juni 2003 @ 14:59:
Je hebt gelijk als ik van te voren zou weten dat elke Person een Man zou zijn, en in dit voorbeeld doe ik ook alleen maar iets met de Man, namelijk secret opvragen. Dan kun je je inderdaad afvragen waarom je geen collection van alleen Man aanmaakt. Maarrrr, misschien dient die collectie wel een ander globaler doel binnen de applicatie.
Een collection dient altijd EEN doel. Heb je een doel D en je hebt daarvoor input A, B en C nodig, dan moet je die aanmaken of verkrijgen. Zo werkt software development, er is niets complex aan, eerder doodsaai. Je gaat dan kijken hoe je aan A, B en C komt en als je die verkrijgen kunt door a) ze bij voorbaat aan te maken wanneer je dat kunt of b) ze kunt opstellen aan de hand van een supercollectie en dan alle objects te bekijken, denk ik dat a) erg efficient is en b) erg dom.
Ik vind het helemaal niet raar dat bijvoorbeeld een ziekenhuis een datastructuur van Patienten heeft, met subtypes Man, Vrouw, en wie weet wat voor subtypes nog meer. Ik vind het dan ook niet raar, dat je dan zon Patient pakt en hem downcast naar dat ding waar je mee wil werken, bijvoorbeeld Man. In jouw geval moet het ziekenhuis allemaal aparte collections gaan bijhouden van elk subtype van Patient, want jij wil er efficient over kunnen itereren.
Wanneer ik er over MOET itereren, ja dan maak ik zo'n subcollectie aan ja. Mijn code is dan ook gegarandeerd altijd het efficientst, ik hoef nl. niet over een enorme bak met patienten te itereren om alle mannen te zoeken, die heb ik nl. al. Heb ik geen code die alleen mannen nodig heeft, dan maak ik die collection niet aan. Die collections heb je niet voor jan joker, die maak je om een bepaald doel te dienen. Een collection 'patienten' is geschikt voor code die met louter het type 'patient' werkt, maar is onnozel voor code die met zwangere vrouwen werkt, want dat wordt zoeken, en dat kost erg veel tijd.

Je kunt dan net zo goed 1 grote bak maken met ALLE objects die je hebt, waarom maak je een specifieke 'person' of 'patienten' collection aan en niet 'objects' en gaat dan alle objects daaruit filteren die je voor een bepaalde bewerking nodig hebt?

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Verwijderd schreef op 08 June 2003 @ 15:06:
Mja STL heeft daar iets voor d8 ik. for_each kun je ook per type doen als ik me niet vergis, maar dat is ff te lang geleden voor me :P
Mja, maar dan doet de compiler wat je anders zelf al moet doen :P
Dus dat maakt niet zoveel uit, hooguit dat er wat efficientere code voor neergezet zou kunnen worden.

[ Voor 41% gewijzigd door ACM op 08-06-2003 15:10 ]


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

EfBe schreef op 08 juni 2003 @ 15:09:
Wanneer ik er over MOET itereren, ja dan maak ik zo'n subcollectie aan ja. Mijn code is dan ook gegarandeerd altijd het efficientst, ik hoef nl. niet over een enorme bak met patienten te itereren om alle mannen te zoeken, die heb ik nl. al.
Maar op het moment dat de collection doorzocht moet worden door je gebruikers kan je, volgens mij, lang niet altijd voorzien hoe een bepaalde opdracht eruit zal zien en dus ook niet welke collection je had moeten hebben en welke je allemaal bij moet houden.
Als er op 100 verschillende (sub)typen gezocht kan worden, via 20 verschillende parameters moet je toch best veel collections bijhouden, die administratie kan je applicatie best wel eens opbreken

Nou vind ik dit voorbeeld trouwens typisch iets waar ze databases voor ontwikkeld hebben, dus zou ik die daar ook zo veel mogelijk voor proberen te gebruiken :)

  • EfBe
  • Registratie: Januari 2000
  • Niet online
ACM schreef op 08 June 2003 @ 14:54:
Ik snap wat je bedoeld, maar op het moment dat er 100 verschillende typen zijn en je er op verschillende niveau's mee moet werken, is het bijhouden van 100 losse collections (en nog een X aantal collections voor de "tussenstap typen") niet heel mooi of handig. Je zult dan niet heel gauw algoritmes op 1 van de 100 loslaten, maar toch.
Zucht. Maak jij 1 grote collection aan voor 'objects' en filtert daaruit de objects 'person' om person bewerkingen te doen en daarna de objects 'man' om de man-related bewerkingen te doen? Nee, je maakt een colleciton 'persons'. Goh, waarom toch.
Nou zullen mannen en vrouwen niet gauw van type veranderen tijdens het proces (hoewel het niet perse onmogelijk is) maar op het moment dat dat wel mogelijk is in je applicatie heb je met die aanpak een groot probleem.
Want dan zou je vrouwen in je man-collectie en mannen in je vrouw-collectie krijgen, terwijl je de type verandering niet of nauwelijks kunt achterhalen vanuit je collections gezien (die pogen een strikte scheiding te houden).
Zelfs in weak typed talen heb je dit niet: een instance heeft een x-aantal typen en creert on the fly niet er een paar bij. Bij vrouwen/mannen die een sexchange operatie ondergaan zul je een nieuw object moeten aanmaken, nl. 1 van het andere geslacht en de data moeten overpompen die gemeenschappelijk is. Je kunt nl. niet een object van het type 'vrouw' transformeren naar het type 'man'.

Allemaal no-brainers. Stel jezelf de vraag nog maar eens honderd keer: waarom je WEL een collection van het type 'persons' aanmaakt maar niet van het type 'objects'.
Ik beweer alleen dat je niet altijd een subcollection _kan_ aanmaken en dat het dus ook niet altijd de meest efficiente manier is om de subcollection te proberen bij te houden :)
Wanneer kan ik NIET een collection van een subtype aanmaken? Ik heb een algoritme A en dat heeft een collection van het type T nodig als input. Ik MOET die collection aanleveren, anders werkt A niet goed. HOE ik die collection verkrijg boeit niet, maar het zou prettig zijn als ik die zo efficient mogelijk bouw. Simpel datastructure management en nadenken over je code. Collections zijn verzamelingen van objects van een bepaald type en die bouw je met een reden. Het "hey met wat prutswerk kan ik hier ook gebruik maken van die collection, moet ik alleen ff filteren"-gekloot is zo intens fout, dat wil je niet weten. Voor je het weet heb je een collection van type T die in alle mogelijke algorithmen wordt gebruikt waar je geen weet van hebt.
Owja, en soms is het, imho, ook niet nodig zoiets aan te maken. Als je in je hele applicatie-executie maar een marginaal aantal keren de hele collectie "foutief" doorloopt en verder vrijwel altijd wel de hele collectie moet hebben is het onzin er een aparte subcollectie voor bij te houden, het kost alleen maar weer extra programmeertijd om dat allemaal en overal netjes bij te houden :)
Bewijs dat maar eens met wat beter bewijs dan zo'n losse pols opmerking want ik heb de grote vrees dat je er flink naast zit.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • Scare360
  • Registratie: Juli 2001
  • Laatst online: 20-08 18:43
Verwijderd schreef op 07 June 2003 @ 17:46:
Ik heb nu al een paar dagen een discussie lopen met wat mensen op het werk over het begrip inheritance. Deze heren hebben een heel unieke kijk op het concept. Ik wil mensen vragen die thuis zijn in de materie, en het liefst er ervaring mee hebben qua design/implementatie, eens te reageren op onderstaande. Graag zoveel mogelijk onderbouwing natuurlijk.

Hier komt het probleem:
We hebben 3 classes, Person, Man en Woman. Vanzelfsprekend erven Man en Woman van Person, en hebben daarnaast nog wat attributen. Voor het gemak maar een slordig paintbrush plaatje.

[afbeelding]

Alleen Man heeft dus een secret, en alleen een vrouw heeft kinderen. Vraag me niet waarom, het gaat ff om het voorbeeld.
De discussie gaat nu eigenlijk over wie de functie GetSecret() moet gaan implementeren

Hun stelling:
Omdat in het echte leven Person een verzameling van mannen en vrouwen is, immers een persoon is altijd een man of vrouw, is het object Person ook de verzameling van Man en Woman. Met andere woorden, Person moet de implementatie leveren van GetSecret() (en ook van GetNrOfChildren() uiteindelijk). Als iemand een object van type Person heeft, en GetSecret() roept, zal dit object zichzelf gaan downcasten naar Man en de secret returnen.

Mijn stelling:
Juist niet, secret is specifiek voor Man, dus daar heeft Person niks mee te maken. Sterker nog, het druist zo'n beetje tegen alle regels in die met OO te maken hebben. Derhalve moet Man de implementatie van GetSecret() leveren.

Ik heb al wat argumenten liggen van beide partijen, maar die geef ik nog ff niet, ik wil graag eerst wat reacties hebben.
Ik denk dat jouw collegae geen ene jota snappen van specialisatie/generalisatie. De normale gang van zaken is:

- Identificatie van klassen
- Identificatie van attributen
- Identificatie van operaties
- Generalisatie

Dan zal de generalisatie klasse Person, dus geen GetSecret operatie implementeren, maar de klasse Man. Het is zelfs zo dat dat GetSecret helemaal niet opgenomen wordt in de Person klasse. Man en Woman hebben deze operatie namelijk helemaal niet als gemeenschappelijk goed.

Echter ligt het aan de toepassing die dit object model gebruikt. Uit eigen ervaring heb ik een dergelijke constructies als jouw collegae voorstellen ook wel eens toegepast. Hierbij werd het object model op een heel hoog abstractie niveau gebruikt en werd door typechecking geverifieerd of de methode aangeroepen mocht worden. Stel je hebt 10 klassen die wel de GetSecret zouden moeten implementeren, en precies 1 klasse niet. Dan is de overweging om die ene klasse een NotImplentedException te laten gooien eerder gemaakt dan alsmaar nieuwe generalisaties te introduceren.

OO-design kent geen best-fit, het komt altijd neer op de vraag "hoe ga ik dit gebruiken".

  • Nappie
  • Registratie: September 2000
  • Laatst online: 03-11-2024

Nappie

Share and enjoy

Het schiet niet zo heel erg op om te gaan bakkeleien over de vraag of je een Person collectie moet nemen of een aparte collectie voor Man en Woman. Dat zal (zoals in vorige posts ook al naar voren kwam) per toepasssing verschillen.

Een opmerking over interfaces: een abstract base class is op geen enkele manier minder een interface dan het Java equivalent. Dat het woordje interface er niet bij staat doet er niet toe. Dat is alleen maar syntax.

Dan nog iets over downcasten of isOfType operaties: normaal gesproken wil je dat niet. Een belangrijk voordeel van het werken met subclasses en virtuals is nou juist dat je je code rechtlijniger kan maken. Normaal gesproken probeer je (met name in C++, Java heeft volgens mij weer een heel andere stijl) zaken zo te regelen dat elke derived class de voor die class specifieke operaties uitvoert. Je algoritme hoort met behulp van RTTI de juiste routines aan te roepen.

Voordelen:
- minder complexe code door minder condities (ja, op een andere manier wordt het natuurlijk weer complexer: meer classes en ingenieuze manieren om van RTTI gebruik te maken zoals Visitors)
- compile-time correctness. En dit is een hele belangrijke! Het is ideaal als je zodanig kan programmeren dat de compiler ervoor zorgt dat de juiste routine wordt aangeroepen via vtables en een fout geeft als dat niet lukt.

Mijn strategie: vermijd "isOfType"-achtige operaties en downcasting zoveel mogelijk. Laat dit lekker door je RTTI uitzoeken. Als je routines allemaal bestaan uit grote conditionals of switches om per subclass iets anders te doen, dan is misschien handig om je ontwerp aan te passen.

Only way to feel the noise is when its good and loud.


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

EfBe schreef op 08 juni 2003 @ 15:19:
HOE ik die collection verkrijg boeit niet, maar het zou prettig zijn als ik die zo efficient mogelijk bouw.
Mja, op het moment dat je ergens if(... instanceof ...) hebt staan _ben_ je die collectie aan het aanmaken...
Dat je dat dan integraal met je algoritme doet kan je als fout beschouwen, maar als dat algoritme maar 1x zo draait is het, imho, niet perse onverstandig.
Bewijs dat maar eens met wat beter bewijs dan zo'n losse pols opmerking want ik heb de grote vrees dat je er flink naast zit.
Goed, de patienten weer:
je hebt een patient -> die heeft een persoon (en een persoon kan een man of een vrouw zijn) als atribuut.

Een patient heeft ook een Reden waarom ie in het ziekenhuis is (Ziekte Z, Letsel L, Controle C, etc)

Nu wil een gebruiker van alle in het ziekenhuis opgenomen vrouwen met HIV weten of ze zwanger zijn of niet. Heb jij van te voren dan handson een collectie met alle vrouwen besmet met HIV? Of een met alle zwangere vrouwen?

En als iemand daarna wil weten welke van die vrouwen de bloedgroep O+ hebben?

Een andere gebruiker wil van alle patienten met HIV weten welke er de bloedgroep O- hebben (is dat een bloedgroep? :) ) en vaker in dit ziekenhuis een bloedtransfusie hebben gekregen.


Ik ben het absoluut met je eens dat het verstandig is de "meest compacte" collection te gebruiken en liefst een die precies voldoet aan je "zoektocht" en die al van te voren aangemaakt is, maar op het moment dat je dat van te voren niet kan weten (en volgens mij zijn bovenstaande gevallen daar voorbeelden van) wat de zoektocht is, kan je niet alle collections van te voren perfect aanmaken.

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Nappie: jij snapt het.

ACM: zoals je zelf al zei: een database doet dat veel beter. Ik ga echt niet in code lopen itereren over een mega collectie om enkele objects eruit te filteren.

Een database heeft echter weer het leuke manko dat je supertype-subtype relaties als waarden in tabellen moet opnemen, wat dus niet in relaties in de database is vastgelegd (en ook maakt dat het relationele model crap is voor OO), en je in feite de iteratie en de test in een sql statement plakt :D.

[ Voor 92% gewijzigd door EfBe op 08-06-2003 15:53 ]

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

EfBe schreef op 08 juni 2003 @ 15:50:
en je in feite de iteratie en de test in een sql statement plakt :D.
Gelukkig kan een fatsoenlijke database daar redelijk tot zeer goed een fatsoenlijke "subcollectie" voor maken (evt mbv een of meerdere indices) :)

Anyway, ik 'ben bang' dat we het gewoon grotendeels eens zijn maar een miniem subjectief meningsverschil uitgebreid proberen uit te leggen :)

  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 22-08 16:45
Nappie schreef op 08 juni 2003 @ 15:33: Je algoritme hoort met behulp van RTTI de juiste routines aan te roepen.
..
Mijn strategie: vermijd "isOfType"-achtige operaties en downcasting zoveel mogelijk. Laat dit lekker door je RTTI uitzoeken. Als je routines allemaal bestaan uit grote conditionals of switches om per subclass iets anders te doen, dan is misschien handig om je ontwerp aan te passen.
In C++ heb je zonder RTTI al je polymorphism (geïmplementeerd door de vtable), dat zorgt ervoor dat de routines van die specifieke subclass worden aangeroepen. Door gebruik te maken van RTTI kan je 'isOfType'-achtige dingen gaan doen met behulp de dynamic_cast.

  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
nog effe:

class A
class B extends A

A tA = (A)B; //Downcast (minder specifiek - compiler check)
B tB = (B)A; //Upcast (mee specifiek - tricky en dus instanceof geval)

Verwijderd

Topicstarter
hobbit_be schreef op 08 juni 2003 @ 16:40:
nog effe:

class A
class B extends A

A tA = (A)B; //Downcast (minder specifiek - compiler check)
B tB = (B)A; //Upcast (mee specifiek - tricky en dus instanceof geval)
Ben ik gek of heb je de zaken omgedraaid hiero.

  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
Verwijderd schreef op 08 June 2003 @ 17:25:
[...]
Ben ik gek of heb je de zaken omgedraaid hiero.
je bent niet gek :) doh... weer iets opgehelderd in my troubled mind (wel ERG slechte naam keuze IMHO)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

hobbit_be schreef op 08 June 2003 @ 17:36:
(wel ERG slechte naam keuze IMHO)
waarom? Als je in een boomstructuur omhoog gaat, dan ga je naar de parent van de huidige node. Een upcast is dan ook een cast naar een generieker type (de superclass is de parent van de subclass). Zie ook het UML tekeningetje in de topicstart. Van specifiek naar generiek is omhoog, dus een upcast

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Nappie
  • Registratie: September 2000
  • Laatst online: 03-11-2024

Nappie

Share and enjoy

Ben ik gek of heb je de zaken omgedraaid hiero.
Jij bent niet gek.

class Base {};
class Derived : public Base {};

Base *p = new Derived();
Derived *q = dynamic_cast<Derived *>(p); // Downcast

Een "Upcast"? Wat is dat?
Als je mijn eerste regel een upcast wil noemen, ga je gang. Maar, zoals je ziet heb je er geen speciale notatie voor nodig. Voor zover mij bekend (ik weet niet zoveel van andere talen dan C++) doe je nooit iets speciaals voor een "upcast". Het hele begrip is overbodig. Eventueel zou je het kunnen hebben over zoiets als generalisatie of zo.

Aanvulling op post van ACM:
In het geval van een patienten database heb je volgens mij nauwelijks een regel om Man en Vrouw apart te houden. Dat zou je daar gewoon in een attribuut geslacht stoppen. Verder heb je natuurlijk helemaal gelijk. Je kan een prima reden hebben voor een collectie van Persons (of Patienten) waarbij je af en toe iets specifieks voor een bepaalde subclass moet doen. Als dat vaak voorkomt, dan ga je natuurlijk een aparte collection bijhouden voor die subclass.

Volgens mij wordt de discussie af en toe wat lastig omdat het originele voorbeeld al een beetje vergezocht is.

Only way to feel the noise is when its good and loud.


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Nappie schreef op 08 juni 2003 @ 18:00:
class Base {};
class Derived : public Base {};

Base *p = new Derived();
Derived *q = dynamic_cast<Derived *>(p); // Downcast

Een "Upcast"? Wat is dat?
Is de upcast dan niet dit:
Base *b = (Base)q; ?
Volgens mij wordt de discussie af en toe wat lastig omdat het originele voorbeeld al een beetje vergezocht is.
Dat is vaak een probleem ja, het is vaak behoorlijk lastig een goed voorbeeld te bedenken :)

  • Buffy
  • Registratie: April 2002
  • Laatst online: 26-12-2024

Buffy

Fire bad, Tree pretty

Volgens mij is de discussie over wel of niet gespecificeerde collectie ook niet relevant voor het probleem van TS. Bij een collectie van objecten van het zelfde type heb je dat namelijk ook. Bv als je een reaper algoritme wilt implementeren die alle personen ouder dan 65 jaar opruimt dan heb je ook de keuze loop ik alle personen af van een collectie van personen met willekeurige leeftijd of onderhoud ik twee collecties bejaard en niet bejaard en voer het reaper algoritme alleen op de bejaard collectie uit.

De laatste optie is alleen mogelijk als je op voorhand weet wat het selectie criteria zijn van het reaper algoritme. Als die altijd het zelfde zijn dan zijn gescheiden collecties verstandiger maar als de criteria kunnen variëren niet.

Een situatie waarin down casting soms nodig is:

Neem een gebouw waar de bewaking een persoon oppakt uit de categorie "gedraagt zich verdacht". Een (professionele) bewaker zal het een worst wezen of het een man of een vrouw betreft en heeft slechts als taak om de persoon naar de ondervrager te brengen.
De ondervrager is geïnteresseerd in dingen als identiteit, leeftijd (eigenschappen persoon) maar niet in het aantal kinderen indien het een vrouw is. Waar een ondervrager wil geïnteresseerd in is, is het mogelijke geheim die de persoon heeft als het een man is.
Nappie schreef op 08 June 2003 @ 18:00:
Volgens mij wordt de discussie af en toe wat lastig omdat het originele voorbeeld al een beetje vergezocht is.
In het door mij geschetste situatie zou het eerder bezoeker en werknemer zijn ipv man en vrouw. Reële eigenschappen zijn dan resp. "afspraak met" en "heeft functie".

That which doesn't kill us, makes us stranger - Trevor (AEon FLux)
When a finger points at the moon, the imbecile looks at the finger (Chinese Proverb)


  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
.oisyn schreef op 08 June 2003 @ 17:51:
[...]
waarom? Als je in een boomstructuur omhoog gaat, dan ga je naar de parent van de huidige node. Een upcast is dan ook een cast naar een generieker type (de superclass is de parent van de subclass). Zie ook het UML tekeningetje in de topicstart. Van specifiek naar generiek is omhoog, dus een upcast
Je ben het gaan opzoeken waarom het zo noemde en dus idd the hierarchie. Tis gewoon dat voor een half - engelse mens als ik het counter-intuitive klinkt: Up = better , down is slechter of minder :) - ook kun je de tree omdraaien ie wat gebeurt in andere sciences (ie van Amoebe tot mens). Mischien zouden ze het gewoon Derived Cast and Base Cast moeten noemen :) ...

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
hobbit_be schreef op 08 June 2003 @ 19:46:
Je ben het gaan opzoeken waarom het zo noemde en dus idd the hierarchie. Tis gewoon dat voor een half - engelse mens als ik het counter-intuitive klinkt: Up = better , down is slechter of minder :) - ook kun je de tree omdraaien ie wat gebeurt in andere sciences (ie van Amoebe tot mens). Mischien zouden ze het gewoon Derived Cast and Base Cast moeten noemen :) ...
Om de verwarring compleet te maken, wordt ook wel eens 'narrowing' (versmallen) gebruikt, om aan te geven dat van een algemeen naar een specifiek object gecast wordt (omdat je een 'smallere' selectie uit het universum neemt).

  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
Soultaker schreef op 08 June 2003 @ 20:10:
[...]
Om de verwarring compleet te maken, wordt ook wel eens 'narrowing' (versmallen) gebruikt, om aan te geven dat van een algemeen naar een specifiek object gecast wordt (omdat je een 'smallere' selectie uit het universum neemt).
en een narrowing is dan een downcast dus? :) ? (want dat is weer met die tree metafoor die je langs twee kanten kunt bekijken). Generalising Cast? MoreSpecific Cast? Eigenlijk wel offtopic...

edit:
Newer and Older casting ?
Thinner and Thicker ?
Richer and Poorer casting?

[ Voor 10% gewijzigd door hobbit_be op 08-06-2003 20:32 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nappie schreef op 08 June 2003 @ 18:00:
Een "Upcast"? Wat is dat?
Als je mijn eerste regel een upcast wil noemen, ga je gang. Maar, zoals je ziet heb je er geen speciale notatie voor nodig. Voor zover mij bekend (ik weet niet zoveel van andere talen dan C++) doe je nooit iets speciaals voor een "upcast".
Dat je er niets voor hoeft te doen komt omdat het impliciet is. Maar dat betekent nog niet dat de cast niet bestaat. Impliciete downcasts kunnen in C++ ook, door een operator te overloaden. Maar dat maakt nog niet dat een "downcast" ook niet bestaat
hobbit_be schreef op 08 June 2003 @ 19:46:
Up = better , down is slechter of minder :)
ja maar hoe plaats je het beter/slechter dan in het generieker/specifieker systeem? Imho is generieker niet 'beter', maar het is ook niet 'slechter'. Imho heeft het daar weinig mee te maken :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
hobbit_be schreef op 08 juni 2003 @ 20:30:
en een narrowing is dan een downcast dus?
Narrow is 'nauwer', oftewel meer specifiek; van Persoon naar Vrouw, dus bijvoorbeeld. De enige cast die nuttig is, want vanwege polymorfie is een Vrouw al automatisch een Persoon. Het tegenovergestelde (broadening?) kan maar beter onbenoemd blijven, dan kan er in ieder geval geen twijfel meer ontstaan over welk begrip nu precies bij welke term hoort. :)
Pagina: 1