Ontwerpkeuzes m.b.t. Generics .NET/Java

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

  • AquilaDus
  • Registratie: Januari 2004
  • Laatst online: 01-11-2025
Zelf programmeer ik vaak in C#. Daarbij gebruik ik vaak generics. Nu moest ik laats ook iets doen in Java en daarbij vielen mij een aantal dingen op in de generic klassen van Java. Ik zal het even duidelijk maken aan de hand van een voorbeeld. Stel we nemen de volgende twee vergelijkbare interfaces:

.NET: System.Collections.Generic.ICollection<T>
Java: java.util.Collection<T>

Beide interfaces definieren een 'add' methode waarmee je een item van het type T kunt toevoegen aan de collection die de interface implementeert. Nu komt het vreemde. Toen ik de 'remove' en 'contains' methode bekeek zag ik op eens dat deze methoden in de .NET interface een item van type T als parameter heeft, maar dat er in Java de parameter gewoon een object o is.

Nu vraag ik me af waar deze verschillen vandaan komen. Wat is het nut om de 'remove' en 'contains' zo te definieren dat ze niet alleen iets van type T accepteren, maar alle mogelijke objecten, want dat lijkt me toch vreemd bij een collectie dat items van het type T bevat. Zijn er mensen die weten waar deze verschillen vandaan komen en waarom het zo gedaan is?

p.s. Ik hoop dat ik het bericht hier thuis hoort, want ik was aan het twijfelen of ik het nu hier of in Programming zou posten.

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 00:32
Dat heeft te maken met backwards compatibility. De Collection api is erbij gekomen in Java 1.2 en toen werden accepteerden alle methods van de Collection- interface Objects. Generics zijn pas toegevoegd in Java 5.0, maar omwille van backwards compatibility hebben ze niet de hele interface aangepast.

Alleen add() is zoals het hoort.

Kijk voor de gein de verschillende API Documentaties van 'Collection' maar eens door:
Java 1.3: http://java.sun.com/j2se/...java/util/Collection.html
Java 1.4.2: http://java.sun.com/j2se/...java/util/Collection.html
Java 1.5.0 (5.0): http://java.sun.com/j2se/...java/util/Collection.html

[ Voor 32% gewijzigd door Jaap-Jan op 16-09-2006 15:36 ]

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


  • Mitt3nz
  • Registratie: Maart 2002
  • Laatst online: 12-02 17:07
Staat allemaal netjes uitgelegd in hoofdstuk 10 van deze Generics tutorial van Sun :) Lees hem eens helemaal door zou ik zeggen.

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Toch wel raar, aangezien ook generics naar standaard arrays en collections gecompileerd worden. Voor een JVM bestaan generics niet eens. Deze backwards compatibility is dus alleen voor mensen die in oude code gaan hacken en dan weer compileren. Persoonlijk zou ik daar niet zo veel rekening mee houden.

Als je namelijk toch opnieuw moet compileren, pas dan ook die paar aanroepen maar ff aan.

Fat Pizza's pizza, they are big and they are cheezy


  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
Dit heeft IMHO niks met backwards compatiblity te maken, maar simpelweg: het maakt voor contains en remove toch niet uit welk type object je aanbiedt, ook al kunnen er alleen objecten van type T aan worden toegevoegd?

Als ik een collection heb van type T en ik vraag of deze een object van type Y bevat, dan krijg ik gewoon false terug en als ik remove aanroep met een object van type Y dan wordt er niks verwijderd, want er zit geen object van type Y in.

Dit is gewoon een kwestie van alleen datgene doen wat nodig is, generics toevoegen aan methodes waarbij dat overbodig is is verspilling van tijd.

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:55
Dit is gewoon een kwestie van alleen datgene doen wat nodig is, generics toevoegen aan methodes waarbij dat overbodig is is verspilling van tijd.
Ik zie niet in hoe je daar tijd aan verspilt ? Als de signature van die method nu Contains (object o) of Contains (T item)is, maakt toch niets uit ivm 'tijdverspilling'.

https://fgheysels.github.io/


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Remus schreef op zondag 17 september 2006 @ 13:38:
Dit heeft IMHO niks met backwards compatiblity te maken, maar simpelweg: het maakt voor contains en remove toch niet uit welk type object je aanbiedt, ook al kunnen er alleen objecten van type T aan worden toegevoegd?

Als ik een collection heb van type T en ik vraag of deze een object van type Y bevat, dan krijg ik gewoon false terug en als ik remove aanroep met een object van type Y dan wordt er niks verwijderd, want er zit geen object van type Y in.
Volgens mij heeft dat twee nadelen:
1) het maakt het maken van compile time fouten makkelijker, doordat je niet doorhebt dat je een verkeerd object doorgeeft aan de contains/remove. Terwijl er weinig (geen?) situaties zijn waarin het zinvol is van een collectie met type parameter T te vragen of er een object van type Y in zit. Als dat kon, dan had je de type parameter niet meegegeven, is het wel? Contains en remove met een generieke parameter leidt tot minder compile time fouten.

2) Je hebt zo een complexere equals methode, inclusief instanceof, nodig. Nu kan je natuurlijk zelf zowel de equals als de contains/remove methoden overriden met versies die alleen een bepaald type accepteren, maar dat is ook weer werk waar fouten in kunnen sluipen.

Kortom, de reden 'dat het niet uitmaakt' lijkt me niet afdoende.

Wie trösten wir uns, die Mörder aller Mörder?


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Mitt3nz schreef op zaterdag 16 september 2006 @ 15:38:
Staat allemaal netjes uitgelegd in hoofdstuk 10 van deze Generics tutorial van Sun :) Lees hem eens helemaal door zou ik zeggen.
Waar staat het volgens jou? Ik heb dat ding net nog maar eens helemaal doorgelezen, maar daar komen de signatures remove(Object o) of contains(Object o) niet in voor.

Wie trösten wir uns, die Mörder aller Mörder?


  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
whoami schreef op zondag 17 september 2006 @ 13:46:
[...]
Ik zie niet in hoe je daar tijd aan verspilt ? Als de signature van die method nu [html]<code>Contains (object o)</code>[/] of [html]<code>Contains (T item)</code>[/]is, maakt toch niets uit ivm 'tijdverspilling'.
Twee manieren van tijdsverspilling:
1) Implementatie
2) Runtime controles

Maar ok, dat is misschien een berg zout op een klein slakje gooien.

Wat ik vermoed dat de voornamelijk reden is voor de implementaite is dat als ik contains implementeer als (T item) in plaats van (Object item) en ik roep contains aan met een object van type Y, dan krijg ik een exception.
Dat de collection alleen objecten van type T bevat, heeft tot gevolg dat er nooit een object van type Y in zit. Als gevolg daarvan is het logisch te noemen dat een aanroep van contains dus ook gewoon false moet teruggeven en dus kan er volstaan worden met een implementatie met (Object item).

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:55
Wat ik vermoed dat de voornamelijk reden is voor de implementaite is dat als ik contains implementeer als (T item) in plaats van (Object item) en ik roep contains aan met een object van type Y, dan krijg ik een exception.
Ik heb geen ervaring met Java, maar als dit zo gebeurt, dan is het IMHO vies. Indien Contains in een generic collection een parameter van het type object bevat, en die generic collection aanvaardt enkel types van het type T, en jij geeft een type Y mee aan contains, dan zou er geen exception mogen gegooid worden, maar gewoon een false gereturned worden.
Indien je hier een exceptie gooit, wil het zeggen dat je dit eigenlijk gewoon niet toelaat; dan had je dit evengoed adhv de compiler kunnen laten afdwingen door Contains ook een parameter van het type T mee te geven, ipv een parameter van het type object.

https://fgheysels.github.io/


  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
whoami schreef op zondag 17 september 2006 @ 16:36:
[...]
Ik heb geen ervaring met Java, maar als dit zo gebeurt, dan is het IMHO vies. Indien Contains in een generic collection een parameter van het type object bevat, en die generic collection aanvaardt enkel types van het type T, en jij geeft een type Y mee aan contains, dan zou er geen exception mogen gegooid worden, maar gewoon een false gereturned worden.
Indien je hier een exceptie gooit, wil het zeggen dat je dit eigenlijk gewoon niet toelaat; dan had je dit evengoed adhv de compiler kunnen laten afdwingen door Contains ook een parameter van het type T mee te geven, ipv een parameter van het type object.
Ik poneer een fictieve situatie waarbij contains gedefinieerd is als (T item), in die fictieve situatie zou het aanbieden van object van type Y bij mijn weten een exception opgooien. In de implementatie in Java met (Object item) gebeurt dat dus niet.
Never mind, dit geeft natuurlijk geen runtime exception, maar slechts compile time fouten. Ik ben een beetje in de war denk ik.

[ Voor 6% gewijzigd door Remus op 17-09-2006 16:55 ]


  • Mitt3nz
  • Registratie: Maart 2002
  • Laatst online: 12-02 17:07
Confusion schreef op zondag 17 september 2006 @ 14:16:
[...]

Waar staat het volgens jou? Ik heb dat ding net nog maar eens helemaal doorgelezen, maar daar komen de signatures remove(Object o) of contains(Object o) niet in voor.
Dan zou ik pagina 21 iets beter bekijken als ik jou was ;)

[ Voor 19% gewijzigd door Mitt3nz op 20-09-2006 10:31 ]


  • MaxxRide
  • Registratie: April 2000
  • Laatst online: 09-01 10:13

MaxxRide

Surf's up

Er is nog een opmerkelijk feit.

Stel dat je type T een value type is, namelijk int32. Deze wordt op de stack bewaard. Ga je nu een remove doen dan zullen alle objecten van type T in een object worden geboxed, gevolg onnodige operaties op de heap.

Buiten dat het in mijn ogen conceptuele onzin is (immers je definieert iets van een type, dan moet je remove ook aan dat type voldoen) geeft he took nog performance verlies.

In mijn ogen is dit in .NET beter opgelost (zie het laatste .NET magazine, staat een leuk artikel in).

If you are not wiping out you are nog pushing enough...


  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
MaxxRide schreef op vrijdag 22 september 2006 @ 22:00:
Er is nog een opmerkelijk feit.

Stel dat je type T een value type is, namelijk int32. Deze wordt op de stack bewaard. Ga je nu een remove doen dan zullen alle objecten van type T in een object worden geboxed, gevolg onnodige operaties op de heap.

Buiten dat het in mijn ogen conceptuele onzin is (immers je definieert iets van een type, dan moet je remove ook aan dat type voldoen) geeft he took nog performance verlies.

In mijn ogen is dit in .NET beter opgelost (zie het laatste .NET magazine, staat een leuk artikel in).
Hoe bedoel je? Int32 bestaat niet in Java en in Java kan je geen primitieve types opnemen in collections, alleen objecten, een dergelijke collection bevat dus al objecten en er vindt geen conversie plaats.

  • MaxxRide
  • Registratie: April 2000
  • Laatst online: 09-01 10:13

MaxxRide

Surf's up

JAVA kent native(primitive) types, boolean, int etc. Dit zijn geen objecten en bevinden zich op de stack ipv in de heap. Wanneer je zo een object in een Collection gooit die Object accepteert zal de compiler/ run-time deze boxen naar een object (er een reference type van maken ipv een value-type). Bij het terugbrengen naar het native type vindt er unboxing plaats.

Tenzij de run-time van JAVA de afgelopen jaren geen natives meer kent maar alleen nog maar object types blijft dit argument dus staan.

If you are not wiping out you are nog pushing enough...


  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
MaxxRide schreef op zaterdag 23 september 2006 @ 22:50:
JAVA kent native(primitive) types, boolean, int etc. Dit zijn geen objecten en bevinden zich op de stack ipv in de heap. Wanneer je zo een object in een Collection gooit die Object accepteert zal de compiler/ run-time deze boxen naar een object (er een reference type van maken ipv een value-type). Bij het terugbrengen naar het native type vindt er unboxing plaats.

Tenzij de run-time van JAVA de afgelopen jaren geen natives meer kent maar alleen nog maar object types blijft dit argument dus staan.
Ik begrijp je argument niet helemaal, aangezien een collection (of die nou gebruik maakt van Generics of niet) in java altijd een Object vereist.

  • AquilaDus
  • Registratie: Januari 2004
  • Laatst online: 01-11-2025
Als de Java keuze iets te maken zou hebben met backwards compatibility, dan vind ik het nog een beetje vreemd. Waarom hebben ze dan niet dezelfde keuze gemaakt als .NET, waarbij men heeft gekozen om de oude niet-generic klassen te laten bestaan en een nieuwe namespace te creeeren met daarin generic collecties.

Ik vind het gewoon heel vreemd dat je generic klassen hebt en dat er in die klassen dan methodes opduiken die niet alleen iets van type T accepteren, maar opeens alle mogelijke objecten. Dan verlies je juist die compile time checks die generics je bieden.

  • MaxxRide
  • Registratie: April 2000
  • Laatst online: 09-01 10:13

MaxxRide

Surf's up

Remus schreef op maandag 25 september 2006 @ 12:38:
[...]

Ik begrijp je argument niet helemaal, aangezien een collection (of die nou gebruik maakt van Generics of niet) in java altijd een Object vereist.
Dat is inderdaad op dit moment de implementatie in JAVA.

Wat gebeurd er onder water: er wordt een value type (native type) of reference type( Object) in de generic gegooid. Indien het reeds een Object is gebeurd er niets, prima. Is het een Native type dan wordt deze vertaald naar haar equivalent in Object vorm (boxing).

Wat is nou het voordeel van de definitie van type T?
1) Strongly typed
2) Compile-time controle ipc run-time

en 3 (in de .NET oplossing) je kunt een value type variant maken en een Object type variant. Voor de value types wordt voor ieder value type een eigen implementaite in de run-time gemaakt (simpelweg omdat booleans anders werken dan ints). Voordeel: de value types hoeven niet naar de heap te worden geplaatst maar mogen op de stack blijven.

Ik hoop dat je nu begrijpt dat de JAVA ontwikkelaars hebben gekozen om een Object te ontvagen. Naar mijn mening is het mooier (maar complexer) om een willekeurig type T te ontvangen.

O-)

If you are not wiping out you are nog pushing enough...

Pagina: 1