[OO] Meerdere return waarden

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

  • Macros
  • Registratie: Februari 2000
  • Laatst online: 21-11 11:06

Macros

I'm watching...

Topicstarter
Soms schrijf ik methodes die 2 dingen returnen. Een versimpeld voorbeeld, je hebt een deel (delen) operatie, die voor ints ook de rest terug geeft in 1 functie. Die is zo omdat je het efficient wilt doen.
Of je zoekt iets in een datastructuur, en als je het vind wil je terug geven het object dat gevonden is en een index. Of voor de iteratie over een map, met key value paren, dan heb je ook altijd 2 objecten.
En erg veel gevallen die je kan bedenken kan het zijn dat je meerdere waardes terug wilt geven. In sommige situaties loont het de moeite om daar een speciale klasse voor de schrijven, zoals Map.Entry, maar soms is dat best wel overkill.

Daarom heb ik voor Java (1.5) deze klassen geschreven:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Tuple <A, B>{
    public final A a;
    public final B b;
    public Tuple(A a, B b){this.a = a;  this.b = b;}
    public A get1(){ return a; }
    public B get2(){ return b; }
    @Override
    public String toString() {
        return "<" + a.toString() + ", " + b.toString() + ">";
    }
}
public class Tuple3<A, B, C> extends Tuple<A, B> {
    public final C c;
    public Tuple3(A a, B b, C c) {
        super(a, b);
        this.c = c;
    }
    public Tuple3(Tuple<A, B> t, C c){
        super(t.a, t.b);
        this.c = c;
    }
    public C get3(){return c;}
    @Override
    public String toString() {
        return "<" + a.toString() + ", " + b.toString() + ", " + c.toString() + ">";
    }
}

Ik gebruik de getX methodes nooit, maar doe direct field accesses. De fields zijn perse final. Helaas kan je een field geen getal naam geven, misschien verander ik het nog "_1".

Eigenlijk vind ik het vreemd dat Java geen Pair class heeft. Ik heb ook nog een static method geschreven die 2 Lists in een List van Pairs maakt en andersom:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    public static <A,B> List<Tuple<A,B>> zip(List<A> listA, List<B> listB){
        if(listA == null || listB == null)
            throw new NullPointerException("Lists can't be null");
        int length = listA.size();
        if(listB.size() != length)
            throw new IllegalArgumentException("List sizes are not equal");
        
        ArrayList<Tuple<A,B>> newList = new ArrayList<Tuple<A,B>>(length);
        if(listA instanceof RandomAccess && listB instanceof RandomAccess){
            for(int i = 0; i < length; i++){
                newList.add(new Tuple<A,B>(listA.get(i), listB.get(i)));
            }
        } else {
            Iterator<A> iter = listA.iterator();
            for (B b : listB) {
                newList.add(new Tuple<A,B>(iter.next(), b));
            }
        }
        return newList;
    }
    
    public static <A,B> Tuple<List<A>, List<B>> unzip(List<Tuple<A,B>> list){
        ArrayList<A> listA = new ArrayList<A>(list.size());
        ArrayList<B> listB = new ArrayList<B>(list.size());
        for (Tuple<A,B> tuple : list) {
            listA.add(tuple.a);
            listB.add(tuple.b);
        }
        return new Tuple<List<A>, List<B>>(listA, listB);
    }

Tuples zijn niet efficient, vooral niet als ze maar kort bestaan of je er heel veel van hebt. Maar zolang je ze buiten tight loops houdt is het te overzien. Mocht zoiets toch voorkomen, kan je het altijd nog vervangen met een echte class. Dat scheelt de cast overhead in de VM, en de wrappers als je primitives gebruikt in je Tuples. Ik heb ook nog een Tuple4 en hogere getallen zijn erg makkelijk om te maken. Het grootste nadeel is dat je geen context informatie hebt in je Tuple objecten. Dus je weet wel wat de types van de waarden in je Tuples zijn, maar niet in welke context. Een String voor elke waarde in elke generic instance van een tuple zou handig zijn, maar ik zou niet weten hoe dat te coden.

Nu de vraag: wat doen jullie in dergelijke gevallen? Maken jullie altijd nieuwe wrapper classjes? Of roep je twee methodes aan voor de twee waardes?

"Beauty is the ultimate defence against complexity." David Gelernter


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Ik gebruik gewoon tuples in C++ die geen overhead hebben... maar anders zou ik output parameters gebruiken. Dus bv. : void prod_sum(int x, int y, int& sum, int& prod) en dan iets soortgelijks in java.

  • Macros
  • Registratie: Februari 2000
  • Laatst online: 21-11 11:06

Macros

I'm watching...

Topicstarter
Dat kan niet in Java.

"Beauty is the ultimate defence against complexity." David Gelernter


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 26-12 16:48

NMe

Quia Ego Sic Dico.

Je topictitel en je vraagstelling suggereren dat de taal voor je vraag niet uitmaakt. Wat wil je dus weten? Hoe mensen het aanpakken in hun eigen, favoriete taal? Of hoe het in Java hoort? :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 21:48

MBV

In PHP geef ik in zo'n geval een array terug. Array's zitten toch wel standaard in Java? Maak een array van meerdere 'object's aan, specificeer in je documentatie wat je teruggeeft, en je bent klaar toch?

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

MBV schreef op zaterdag 19 november 2005 @ 23:46:
In PHP geef ik in zo'n geval een array terug. Array's zitten toch wel standaard in Java? Maak een array van meerdere 'object's aan, specificeer in je documentatie wat je teruggeeft, en je bent klaar toch?
Dat is erg traag in de meeste gevallen.

  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
Zoijar schreef op zaterdag 19 november 2005 @ 23:48:
[...]

Dat is erg traag in de meeste gevallen.
Hoezo? je geeft toch een pointer naar de array terug?

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 26-12 16:48

NMe

Quia Ego Sic Dico.

THIJZEL schreef op zaterdag 19 november 2005 @ 23:49:
Hoezo? je geeft toch een pointer naar de array terug?
Java kent, AFAIK, geen pointers en geen expliciete references. Alles wordt by value doorgegeven.

Maar ik kan er wel eens naastzitten, aangezien ik weinig tot niets met Java heb gedaan. :P

edit:
Iets minder kort door de bocht: http://www.javaworld.com/...0-05/03-qa-0526-pass.html

[ Voor 14% gewijzigd door NMe op 19-11-2005 23:52 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

En hoe blijft die dan bestaan? Dan moet je hem op de heap zetten ipv stack, en dus dynamisch geheugen alloceren -> traag. Anders op de stack, en dan moet je een copy van je array maken, in de meeste gevallen is dat niet triviaal en kan dat niet geoptimized worden.

In java is toch alles in feite een pointer?

[ Voor 10% gewijzigd door Zoijar op 19-11-2005 23:52 ]


  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 02:06
-NMe- schreef op zaterdag 19 november 2005 @ 23:51:
[...]

Java kent, AFAIK, geen pointers en geen expliciete references. Alles wordt by value doorgegeven.

Maar ik kan er wel eens naastzitten, aangezien ik weinig tot niets met Java heb gedaan. :P

edit:
Iets minder kort door de bocht: http://www.javaworld.com/...0-05/03-qa-0526-pass.html
In Java worden primitives by value doorgegeven en objecten met een kopie van een by reference :).

[ Voor 3% gewijzigd door Jaap-Jan op 20-11-2005 00:01 ]

| 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


  • prototype
  • Registratie: Juni 2001
  • Niet online

prototype

Cheer Bear

Zoijar schreef op zaterdag 19 november 2005 @ 23:51:In java is toch alles in feite een pointer?
Nee, in java is alles in feite een reference/value; java heeft geen benul van pointers, daar de JVM alle geheugen management doet. De levensduur van de objecten hangt af van hoeveel referenties er naar zijn; zijn er geen, i.e. null, dan zal de garbage collector korte metten met ze maken.
Verder at TS:
Dus je weet wel wat de types van de waarden in je Tuples zijn, maar niet in welke context. Een String voor elke waarde in elke generic instance van een tuple zou handig zijn, maar ik zou niet weten hoe dat te coden.
Kun je dit nader toelichten?

[ Voor 3% gewijzigd door prototype op 20-11-2005 01:16 ]


  • Macros
  • Registratie: Februari 2000
  • Laatst online: 21-11 11:06

Macros

I'm watching...

Topicstarter
Een array is totaal niet handig vanwege twee redenen:
- als je verschillende types terug wilt geven verlies je typechecking omdat de array de type van de grootste gemene deler heeft en de ontvanger moet de objecten casten
- er is geen garantie van de grote van de array, dus ook een verlies van type checking

Voorbeeld hoe te gebruiken:
Java:
1
2
3
4
5
6
7
public Tuple<Aap, Noot> getAapNoot(){
   return new Tuple<Aap, Noot>(getAap(), getNoot());
}

Tuple<Aap, Noot> an = getAapNoot();
Aap a = an.a;
Noot n = an.b;


Ik koos de tag OO, omdat C# hetzelfde probleem heeft waarschijnlijk.
Java heeft alleen pass by value. Als ik objecten aan een methode geef, dan kan de methode alleen de state van die objecten veranderen. Als de methode de var waar het object 'in' zit veranderd door een assignment, dan wordt de reference van caller van de methode niet veranderd. Dit is in principe ook het idee van pass by value. Als het pass by reference ondersteunde, dan kon dit wel.

"Beauty is the ultimate defence against complexity." David Gelernter


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 26-12 16:48

NMe

Quia Ego Sic Dico.

In C# kun je gewoon variabelen by reference doorgeven, althans, dat maak ik op uit deze pagina. :P Dus ik denk dat je probleem redelijk Java-specifiek is. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

prototype schreef op zondag 20 november 2005 @ 01:15:
[...]

Nee, in java is alles in feite een reference/value;
java heeft geen benul van pointers, daar de JVM alle geheugen management doet.
En wat is het verschil tussen een pointer en een reference? Juist, is er niet, het zijn beide naampjes voor hetzelfde concept (muv C++, maar een C++ reference kun je het ook niet noemen aangezien je die niet naar iets anders kunt laten wijzen, wat in java wel kan). Het geheel wijst naar een object, en of dat geïmplementeert wordt met een pointer naar een stuk geheugen of met een index in een array, het blijft een verwijzing, hence pointer.
-NMe- schreef op zondag 20 november 2005 @ 02:12:
In C# kun je gewoon variabelen by reference doorgeven, althans, dat maak ik op uit deze pagina. :P Dus ik denk dat je probleem redelijk Java-specifiek is. :)
Plus dat je in C# value-type objects hebt die je net als in C++ gewoon by-value kunt returnen, hence weinig overhead. Ik moet zeggen dat ik deze aanpak ook prefereer bij de bekende parseInt() functie, ipv een exception

[ Voor 38% gewijzigd door .oisyn op 20-11-2005 03:06 ]

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.


  • prototype
  • Registratie: Juni 2001
  • Niet online

prototype

Cheer Bear

.oisyn schreef op zondag 20 november 2005 @ 03:03:
[...]

En wat is het verschil tussen een pointer en een reference? Juist, is er niet, het zijn beide naampjes voor hetzelfde concept (muv C++, maar een C++ reference kun je het ook niet noemen aangezien je die niet naar iets anders kunt laten wijzen, wat in java wel kan). Het geheel wijst naar een object, en of dat geïmplementeert wordt met een pointer naar een stuk geheugen of met een index in een array, het blijft een verwijzing, hence pointer.
Sorry, maar het verschil -hoe subtiel het ook moge zijn- noem je nu toch zelf al? Hetgeen ik ook wilde aankaarten. Zo kun je met pointers doordat ze naar geheugenadressen verwijzen nog mee 'rekenen', itt references.

[ Voor 10% gewijzigd door prototype op 20-11-2005 03:22 ]


  • Macros
  • Registratie: Februari 2000
  • Laatst online: 21-11 11:06

Macros

I'm watching...

Topicstarter
Pointers en references zijn hetzelfde als je de definities gelijk maakt (echt een duh! uitspraak). Maar een redelijke definitie van beide zou kunnen zijn:
References
- hebben geen waarde waar de programmeur bij kan, doel van de reference kan verplaatst worden door het runtime systeem
- kunnen alleen valide waarden bevatten door getype checked assignments of null
Pointers
- programmeur kan waarde inspecteren en veranderen, (p++, p+1, p-1, p = (void *) 4)
- runtime systeem kan de objecten waar de pointers naar wijzen niet veranderen
- kunnen invalide waarden bevatten

Wordt tijd dat Java ook references gaat ondersteunen dan. Eigenlijk vind ik van niet. Het maakt het lastiger te begrijpen voor veel programmeurs. En ik denk niet dat de VM het ondersteund.

"Beauty is the ultimate defence against complexity." David Gelernter


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 26-12 16:48

NMe

Quia Ego Sic Dico.

Macros schreef op zondag 20 november 2005 @ 03:25:
Wordt tijd dat Java ook references gaat ondersteunen dan. Eigenlijk vind ik van niet. Het maakt het lastiger te begrijpen voor veel programmeurs. En ik denk niet dat de VM het ondersteund.
En nu mis je juist een belangrijk taalelement. Pointers en references zijn misschien een lastiger concept om te begrijpen, vooral voor een beginnende programmeur, maar dat mag IMO geen reden zijn om pointers en/of references uit de taal te houden. Het biedt een heel scala aan extra mogelijkheden waar je anders maar lastig voor moet doen, zoals uit dit topic eigenlijk best mooi blijkt. :)

Dit gaat trouwens redelijk offtopic. Ik weet niet of Macros dat erg vindt, aangezien hij zelf meediscussiëert, maar misschien is het fijner om eerst even de daadwerkelijke probleemstelling van dit topic uit te werken.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • prototype
  • Registratie: Juni 2001
  • Niet online

prototype

Cheer Bear

Macros schreef op zondag 20 november 2005 @ 02:00:

Java heeft alleen pass by value. Als ik objecten aan een methode geef, dan kan de methode alleen de state van die objecten veranderen. Als de methode de var waar het object 'in' zit veranderd door een assignment, dan wordt de reference van caller van de methode niet veranderd. Dit is in principe ook het idee van pass by value. Als het pass by reference ondersteunde, dan kon dit wel.
Anders gezegd, de parameters die je aan een methode geeft, zijn kopietjes van de originele reference en worden gepassed als value.

  • Macros
  • Registratie: Februari 2000
  • Laatst online: 21-11 11:06

Macros

I'm watching...

Topicstarter
Volgens mij is deze discussie al een paar keer hier gehouden dus we kunnen er mee door gaan als er nieuwe inzichten ontstaan, maar ik denk het niet.
Mijn originele vraag was vooral hoe programmeurs omgaan met meerdere return waarden in talen zoals Java waar methodes met by reference argumenten niet mogelijk zijn.

"Beauty is the ultimate defence against complexity." David Gelernter


  • whoami
  • Registratie: December 2000
  • Laatst online: 07:42
Macros schreef op zondag 20 november 2005 @ 02:00:
Ik koos de tag OO, omdat C# hetzelfde probleem heeft waarschijnlijk.
Java heeft alleen pass by value. Als ik objecten aan een methode geef, dan kan de methode alleen de state van die objecten veranderen. Als de methode de var waar het object 'in' zit veranderd door een assignment, dan wordt de reference van caller van de methode niet veranderd. Dit is in principe ook het idee van pass by value. Als het pass by reference ondersteunde, dan kon dit wel.
C# kent output parameters.

https://fgheysels.github.io/


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Macros schreef op zondag 20 november 2005 @ 03:25:
Pointers en references zijn hetzelfde als je de definities gelijk maakt (echt een duh! uitspraak). Maar een redelijke definitie van beide zou kunnen zijn:
References
- hebben geen waarde waar de programmeur bij kan, doel van de reference kan verplaatst worden door het runtime systeem
- kunnen alleen valide waarden bevatten door getype checked assignments of null
Pointers
- programmeur kan waarde inspecteren en veranderen, (p++, p+1, p-1, p = (void *) 4)
- runtime systeem kan de objecten waar de pointers naar wijzen niet veranderen
- kunnen invalide waarden bevatten

Wordt tijd dat Java ook references gaat ondersteunen dan. Eigenlijk vind ik van niet. Het maakt het lastiger te begrijpen voor veel programmeurs. En ik denk niet dat de VM het ondersteund.
Dit klopt niet echt... Zo kan een reference geen 'null' bevatten, daarentegen kan een reference wel ongeldig zijn (dangling na een delete bv), een pointer kan ook verplaatst worden als je GC gebruikt, de waarde van een pointer mag je eigenlijk niet vanuit gaan (maar het kan wel ok). Het beste vergelijk is dat een reference een eenmalige hardlink is die niet veranderd kan worden, en een pointer een softlink. Een reference is (een ander naam/alias voor) het object, een pointer is de locatie van heteen object.

Maar mijn opmerking doelde op het feit dat in java dus alles als reference/pointer wordt doorgegeven, en dat die by-value gaan heb je gelijk in. Maar niets weerhoudt je dus om dit soort code te schrijven (ik ken even niet de precieze java syntax):

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void sum(int x, int y, Integer sum, Integer prod) {
   sum.value(x+y);
   prod.value(x*y);
}

Integer s, p;
sum(1, 2, s, p);

// of:
class result {
   int sum, prod;
};

void sum(int x, int y, result r) {
   result.sum = x+ y; result.prod = x*y;
// eventueel return by value: return result(x+y, x*y); // wordt toch wel geoptimized
}

result r;
sum(1, 2, r);

result r(sum(1,2));

Maar dat laatste is in feite hetzelfde als met pairs/tuples werken. Dat je in het object shrijft is geen verlies; een return waarde moet anders ook op de stack gepushed worden en naar geheugen geschreven. En als een optimizer registers gebruikt, dan zorgt hij ook wel dat de object values in registers blijven als ze meteen weer gebruikt worden.

in C++ doe je overigens dus dit:
C++:
1
2
3
4
5
6
std::pair<int, int> sum(int x, int y) {
   return std::make_pair(x+y, x*y);
}

int s, p;
boost::tie(s, p) = sum(1,2);

Wat een mooie taal is het toch ;)

[ Voor 7% gewijzigd door Zoijar op 20-11-2005 11:30 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Macros schreef op zondag 20 november 2005 @ 03:25:
Pointers en references zijn hetzelfde als je de definities gelijk maakt (echt een duh! uitspraak). Maar een redelijke definitie van beide zou kunnen zijn:
References
- hebben geen waarde waar de programmeur bij kan, doel van de reference kan verplaatst worden door het runtime systeem
- kunnen alleen valide waarden bevatten door getype checked assignments of null
Pointers
- programmeur kan waarde inspecteren en veranderen, (p++, p+1, p-1, p = (void *) 4)
- runtime systeem kan de objecten waar de pointers naar wijzen niet veranderen
- kunnen invalide waarden bevatten
Ja, zo zou ik ook nog wel wat random definities kunnen verzinnen :). Als je 'm per se uit C++ wilt halen, die volgens mij überhaupt met het verschil kwam, neem 'm dan goed over zoals Zoijar al aangaf, en dan zie je ook meteen dat die dingen van java geen references zijn. Overigens stelt de C++ standaard ook nog eens dat p = (void *) 4 een 4 reinterpret_cast naar een void*, maar dat dat helemaal niet wil zeggen dat dat het geheugen op adres 4 is. Er wordt slechts gesteld dat er een mapping bestaat van pointer naar een integral type en weer terug. En arithmetic op pointers is undefined als ze niet uit dezelfde allocatie komen. Dus wat je dan overhoudt is een convenience om met pointers als iterators in een array te werken. En is een smart pointer implementatie dan geen pointer? Daar kun je meestal ook niet mee rekenen.

Ik zie niet het verschil tussen een java "pointer" en een boost::shared_ptr. En die laatste heet toch ook een pointer. Het enige verschil tussen pointer en reference is imho dat die laatste een wat generiekere term is.

.edit: En als klap op de vuurpijl: http://en.wikipedia.org/wiki/Pointer
In computer science, a pointer is a programming language datatype whose value refers directly to ("points to") another value stored elsewhere in the computer memory using its address. Obtaining the value that a pointer refers to is called dereferencing the pointer. A pointer is a simple implementation of the general reference datatype (although it is quite different from the facility referred to as a reference in C++).
http://en.wikipedia.org/w...ce_%28computer_science%29
In computer science, a reference is a small object containing information which refers to data elsewhere, as opposed to containing the data itself. Accessing the value that a reference refers to is called dereferencing it. References are fundamental in constructing many data structures and in exchanging information between different parts of a program.

[ Voor 31% gewijzigd door .oisyn op 20-11-2005 15:51 ]

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.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

.oisyn schreef op zondag 20 november 2005 @ 15:43:
. Overigens stelt de C++ standaard ook nog eens dat p = (void *) 4 een 4 reinterpret_cast naar een void*, maar dat dat helemaal niet wil zeggen dat dat het geheugen op adres 4 is. Er wordt slechts gesteld dat er een mapping bestaat van pointer naar een integral type en weer terug. En arithmetic op pointers is undefined als ze niet uit dezelfde allocatie komen. Dus wat je dan overhoudt is een convenience om met pointers als iterators in een array te werken.
Een andere rede hiervoor is dat je zo pointers op kan slaan in (sorted) associative containers: je kan pointers sorteren en ze dan in o(log n) vinden. Hoewel ik niet helemaal zeker weet of dit mag, maar volgens mij voldoen pointers zo aan een strict weak ordering. anyway, lichtelijk off-topic...

  • momania
  • Registratie: Mei 2000
  • Laatst online: 07:22

momania

iPhone 30! Bam!

Macros schreef op zondag 20 november 2005 @ 05:24:
Mijn originele vraag was vooral hoe programmeurs omgaan met meerdere return waarden in talen zoals Java waar methodes met by reference argumenten niet mogelijk zijn.
Niet...

Ik ben wel eens tot een punt aangelopen dat een methode meerdere return values nodig had, maar door wat refactoren kan je dat vaak toch wel weer makkelijk tot 1 terug brengen.

Ik zie zelf ook eigenlijk een methode met meerdere return values (anders dan bijv een collectie met dezelfde elementen) gewoon als een verkeerd design.

Neem je whisky mee, is het te weinig... *zucht*


  • Macros
  • Registratie: Februari 2000
  • Laatst online: 21-11 11:06

Macros

I'm watching...

Topicstarter
Momania, jij programmeert dus niet meer met OO? Je refactored alles zodat je alleen maar scalar waarden gebruikt? Want objecten en structs zijn eigenlijk tuples.

"Beauty is the ultimate defence against complexity." David Gelernter


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

Confusion

Fallen from grace

Macros schreef op zondag 20 november 2005 @ 18:52:
Momania, jij programmeert dus niet meer met OO? Je refactored alles zodat je alleen maar scalar waarden gebruikt? Want objecten en structs zijn eigenlijk tuples.
Een object referentie is een return value. Maar als je èn een object èn een statuscode wilt teruggeven en die statuscode hoort expliciet niet bij het object, dan zal je dus iets anders moeten verzinnen, anders heb je twee return values nodig.
-NMe- schreef:
Pointers en references zijn misschien een lastiger concept om te begrijpen, vooral voor een beginnende programmeur, maar dat mag IMO geen reden zijn om pointers en/of references uit de taal te houden.
De reden om ze uit Java te laten is volgens mij geweest dat het ook voor experts lastig te begrijpen is, gezien het aantal fouten dat ze er mee blijven maken. ;)

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


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 26-12 16:48

NMe

Quia Ego Sic Dico.

Confusion schreef op zondag 20 november 2005 @ 19:22:
De reden om ze uit Java te laten is volgens mij geweest dat het ook voor experts lastig te begrijpen is, gezien het aantal fouten dat ze er mee blijven maken. ;)
Ongetwijfeld, maar dat vind ik geen excuus om ze er maar uit te laten. In situaties waar je ze nodig hebt, moet je nu met allerlei "vieze" hacks werken...lijkt me niet echt fijn. :P Maar dat zeg ik als buitenstaander die gewend is wel de luxe van expliciete references te hebben. :P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 04:08
Ik moet het met .oisyn eens zijn dat 'definities' zoals Macros ze stelt nogal willekeurig zijn. Het zou makkelijk zijn als er een eenduidige definitie van 'pointer' en 'reference' zou zijn, maar helaas is dat gewoon niet zo. Een 'reference' in Java is een significant ander concept dan een 'reference' in C++, maar ook dan een 'pointer' in C, terwijl die C-pointer weer verschilt van een pointer in Pascal.

Het getuigt m.i. van weinig inzicht in de pluriformiteit van programmeertalen om te stellen dat Java 'geen pointers' heeft (of die wel zou moeten hebben). Je kunt hooguit omschrijven welk concept je mist.
Confusion schreef op zondag 20 november 2005 @ 19:22:
De reden om ze uit Java te laten is volgens mij geweest dat het ook voor experts lastig te begrijpen is, gezien het aantal fouten dat ze er mee blijven maken. ;)
Als je de ontwerpfilosofie van Java (en ook .NET trouwens) begrijpt, dan zou je moeten kunnen inzien dat een aantal operaties op pointers die C/C++ wel kent gewoon niet in te passen zijn in een platform als Java.

Java is ontworpen om een gesloten systeem te zijn dat ingebed is in een virtual machine. Op elk moment kan de virtual machine de status van het programma inzien. (De garbage collector is ook gebaseerd op het uitgangspunt dat 'ie precies kan zien welke objecten wel en niet gebruikt worden door de applicatie.) Vanuit security-oogpunt (bijvoorbeeld wanneer Java applets geïntegreed worden in een webpagina, of servlets op een webserver) is het van groot belang dat een applicatie niet buiten zijn leefomgeving kan komen of die kan laten crashen.

Daarvoor is het van belang dat de virtual machine alle acties van de applicaties kan controleren. Om te voorkomen dat een proces geheugen gebruikt dat het niet zelf gealloceerd heeft, zou je alle pointer dereferences moeten controleren. Dat is heel kostbaar natuurlijk. Het is gelukkig makkelijker om ervoor te zorgen dat de applicatie nooit ongeldige pointers kan genereren: doordat met pointers in Java niet gerekend kan worden, en pointers niet geconverteerd kunnen worden naar integers en weer terug. Java initialiseert dus alle pointervariabelen op null, met new kunnen nieuwe, geldige pointers verkregen worden en verder kunnen alleen bestaande pointerwaarden aan pointervariabelen worden toegekend. In C++ kun je een pointerwaarde ongeldig maken door het object vrij te geven, maar in Java kan dat dat niet omdat die taak voorbehouden is aan de garbage collector die dat pas doet als de applicatie juist geen referenties (direct of indirect) meer heeft naar een object.

Op die manier is het systeem dus gesloten en kan een applicatie geen ongeldige pointer maken en hoeft de virtual machine daar dus ook nooit meer op te controleren. Die controleerbaarheid is de reden dat Java beperkingen oplegt aan operaties op pointers (of references, of hoe je ze wil noemen), niet dat die operaties te ingewikkeld zouden zijn voor de programmeur ofzoiets.

En om nu op het hoofdonderwerp terug te komen: de mogelijkheid om maar een enkele waarde terug te geven en het gebrek aan tuples is een typische beperking van de taal Java en niet van het platform Java. Je kunt er zelf tooltjes voor hacken, zoals de topicstarter heeft gedaan, maar een andere programmeertaal zoals Nice ondersteund uit zichzelf al tuples en compileert toch naar Java bytecode.

[ Voor 4% gewijzigd door Soultaker op 20-11-2005 20:29 ]


  • momania
  • Registratie: Mei 2000
  • Laatst online: 07:22

momania

iPhone 30! Bam!

Macros schreef op zondag 20 november 2005 @ 18:52:
Momania, jij programmeert dus niet meer met OO? Je refactored alles zodat je alleen maar scalar waarden gebruikt? Want objecten en structs zijn eigenlijk tuples.
Nee, ik bedoel het meer zoals Confusion al aangeeft.

Natuurlijk kan je een methode een object terug laten geven, maar als je daarnaast idd ook nog een soort van status code oid nodig heeft, die niets met het object te maken heeft, of volgens je ontwerp niet in het object thuis hoort, dan twijfel ik aan het ontwerp.

Methodes moeten vaak doen hoe ze genoemd zijn. Vaak dus een getXXXX, createXXXX, processXXXX, handleXXXX etc...
Een get geeft mij iets, een create maakt iets voor me... van die methodes kan ik dus ook alleen maar verwachten dat ze 1 waarde terug geven. Meerdere return values zie ik daar geen mogenlijkheid en nut voor. Ik maak geen methodes als: getXXXandYYY() :)

Van een methode verwacht ik verder dat hij doet wat hij moet doen. Als er ergens iets mis mee gaat verwacht ik een exception, en geen extra return value.
Afhankelijk van de exception kan je dan bepalen of het een severe iets is of alleen maar warning waardig.

Neem je whisky mee, is het te weinig... *zucht*


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Soultaker schreef op zondag 20 november 2005 @ 20:28:
Op die manier is het systeem dus gesloten en kan een applicatie geen ongeldige pointer maken en hoeft de virtual machine daar dus ook nooit meer op te controleren. Die controleerbaarheid is de reden dat Java beperkingen oplegt aan operaties op pointers (of references, of hoe je ze wil noemen), niet dat die operaties te ingewikkeld zouden zijn voor de programmeur ofzoiets.
Ingewikkeld kun je ook omschrijven als het feit dat iemand niet uit de code kan opmaken wat de code (logischerwijs) moet doen. Dat is iets wat in PHP/C++ regelmatig gebeurt omdat je globale variabelen hebt en omdat mensen variabelen overal vandaan kunnen wijzigen en slopen. Komt de testbaarheid zeker niet ten goede, en dat heeft niet te maken met de moeilijkheidsgraad van de taal.
Soultaker schreef op zondag 20 november 2005 @ 20:28:
En om nu op het hoofdonderwerp terug te komen: de mogelijkheid om maar een enkele waarde terug te geven en het gebrek aan tuples is een typische beperking van de taal Java en niet van het platform Java. Je kunt er zelf tooltjes voor hacken, zoals de topicstarter heeft gedaan, maar een andere programmeertaal zoals Nice ondersteund uit zichzelf al tuples en compileert toch naar Java bytecode.
Ik vind de naam "hack" een beetje ontoepasselijk voor de taal Java. Ik programmeer er nu al weer een aantal jaren mee en ik ben ervan overtuigd dat als je model goed klopt, dat je geen hacks nodig hebt en Java maakt het je alleen maar makkelijk om hacks te vermijden, juist dankzij het niet toestaan van het wijzigen van referenties en zo.

Als je twee waarden wil returnen uit je methode, maak er dan een kleine containerklasse omheen die beide waarden bevat. Als de waarden die je returnt, enigszins verband hebben (en dus zinnig gekozen zijn :)) kun je waarschijnlijk nog wel een extra invulling vinden voor die klasse. Bijvoorbeeld in het geval van een Statement en een ResultSet (toevallig ooit eens nodig gehad) een goede methode om ze allebei te closen zonder excepties.

Op die manier blijft je code schoon, staan er geen zaken waar ze niet horen te staan en is alles veel beter testbaar en schaalbaar. (plus het is OO en dat klinkt altijd wel leuk :))

edit:
@momania: ben ik het mee eens :)

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


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 04:08
momania schreef op zondag 20 november 2005 @ 23:06:
Methodes moeten vaak doen hoe ze genoemd zijn. Vaak dus een getXXXX, createXXXX, processXXXX, handleXXXX etc...
Een get geeft mij iets, een create maakt iets voor me... van die methodes kan ik dus ook alleen maar verwachten dat ze 1 waarde terug geven. Meerdere return values zie ik daar geen mogenlijkheid en nut voor. Ik maak geen methodes als: getXXXandYYY() :)
Die get...() methoden zijn in principe alleen maar getters voor attributen (ook eigenlijk al een beetje een hack omdat Java uit zichzelf geen getters/setters of read-only attributen ondersteund, zoals C# bijvoorbeeld wel doet). Logisch dat die precies één attribuut opleveren.

Return values worden echter ook gebruikt om het resultaat van een operatie terug te geven. Als je één 'entiteit' retourneert (bijvoorbeeld een punt, of een graaf) dan is het logisch dat je een object retourneert (en bijvoorbeeld in het geval van een punt geen x,y-paar), maar er zijn ook genoeg gevallen waarin de data die je terug wil geven geen zinnige entiteit vormt.

De topic starter stelt terecht dat Java op dat punt tekort schiet, want voor elk resultaat moet je dan een aparte klasse maken en dat is fundamenteel verkeerd als zo'n klasse niets anders doet dan objecten vasthouden en dus géén eigen gedrag heeft.
Van een methode verwacht ik verder dat hij doet wat hij moet doen. Als er ergens iets mis mee gaat verwacht ik een exception, en geen extra return value.
Afhankelijk van de exception kan je dan bepalen of het een severe iets is of alleen maar warning waardig.
Daar ben ik het mee eens, maar dat suggereert dat een tupel alleen gebruikt zou worden om een foutmelding en een resultaat terug te geven. Dat is natuurlijk niet de bedoeling. Trouwens, een exception is bedoeld voor 'uitzonderlijke' situaties, dus je moet ook weer uitkijken dat je niet allerlei rare exceptions gaat gooien die onderdeel vormen van een normaal gebruikspatroon.
JKVA schreef op zondag 20 november 2005 @ 23:06:
Ingewikkeld kun je ook omschrijven als het feit dat iemand niet uit de code kan opmaken wat de code (logischerwijs) moet doen.
Accoord, maar mijn punt is juist dat die 'ingewikkeldheid' niet terzake doet: de genoemde pointeroperaties zitten er niet in omdat het niet in het ontwerp past en niet, zoals Confusion suggereerde, omdat het ingewikkeld zou zijn voor de programmeurs - hoe je 'ingewikkeld' ook wil omschrijven. De programmeur had daar niet zoveel mee te maken; sowieso is Java-het-executieplatform niet echt gericht op de eindgebruiker: de programmeur in Java-de-taal.
Ik vind de naam "hack" een beetje ontoepasselijk voor de taal Java.
Noem het hoe je wil. De topicstarter implementeert een concept (namelijke generieke paren/tupels) die niet door de taal of de standaardlibrary ondersteund worden; ik noem het een hack, vooral ook omdat het niet helemaal lekker integreert met bestaande Java code (er is geen handige syntax voor, zoals Nice dat bijvoorbeeld wel heeft).
Als je twee waarden wil returnen uit je methode, maak er dan een kleine containerklasse omheen die beide waarden bevat.
Ik vind dat dus afdoen aan het OO-gebruik. De enige reden dat die klasse bestaat is dat jij toevallig die waarden wil bundelen; als abstract concept bestaat de klasse niet. Als je op papier eerst een klassendiagram uitdenkt zal zo'n hulpklasse er ook niet inzitten. Sterker nog: als Java tuples zou ondersteunen zou je die hele klasse achterwege laten, ook omdat ze geen enkel gedrag vertonen.
Op die manier blijft je code schoon, staan er geen zaken waar ze niet horen te staan en is alles veel beter testbaar en schaalbaar. (plus het is OO en dat klinkt altijd wel leuk :))
Zomaar loze klassen introduceren omdat dat toevallig uitkomt vind ik nu niet echt 'schoon'. Verder denk ik dat zo'n containerklasse testen vrij zinloos is (net zoals een specifieke instantie van de Tuple van de topicstarter) en wat het met schaalbaarheid te maken heeft ontgaat me helemaal. Kun je hier wat argumenten bij geven? Vergelijk dan graag je ad-hoc klasse met het gebruik van een tupel zoals in Nice of een generieke klasse zoals die van de topicstarter.

[ Voor 3% gewijzigd door Soultaker op 20-11-2005 23:35 ]


  • momania
  • Registratie: Mei 2000
  • Laatst online: 07:22

momania

iPhone 30! Bam!

Soultaker schreef op zondag 20 november 2005 @ 23:33:
[...]
maar er zijn ook genoeg gevallen waarin de data die je terug wil geven geen zinnige entiteit vormt.
Kan je daar ook een voorbeeld van geven miscshien? Ik heb het zelf nml. nog _nooit_ nodig gehad. :)

Neem je whisky mee, is het te weinig... *zucht*


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Soultaker schreef op zondag 20 november 2005 @ 23:33:
[...]
Zomaar loze klassen introduceren omdat dat toevallig uitkomt vind ik nu niet echt 'schoon'. Verder denk ik dat zo'n containerklasse testen vrij zinloos is (net zoals een specifieke instantie van de Tuple van de topicstarter) en wat het met schaalbaarheid te maken heeft ontgaat me helemaal. Kun je hier wat argumenten bij geven? Vergelijk dan graag je ad-hoc klasse met het gebruik van een tupel zoals in Nice of een generieke klasse zoals die van de topicstarter.
Ik zeg ook niet dat je loze klasses moet introduceren, maar wel dat je een zinnige waarde teruggeeft. Als dat niet mogelijk is, dan klopt het model niet. Als die twee waarden een samenhangend geheel vormen (wat je bij OO naar mijn idee wil) kun je er ook een klasse omheen schrijven met extra invulling behalve wat getters en setters. Zie voorbeeld resultset en statement in mijn vorige post. (ik weet het, het is niet het sterkste voorbeeld, maar ik maak eigenlijk nooit mee dat ik twee waarden moet teruggeven)

Op die manier is het wel OO, want ze hebben niet alleen als hack nut, maar ook "als abstract concept".

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


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 21:48

MBV

Er staat dus een voorbeeld eerder: integers delen en de rest teruggeven. Als je dat in 1x doet is dat sneller. Tuurlijk is dit voorbeeld te simplistisch, maar er zijn soortgelijke voorbeelden waarbij je wél lang aan het rekenen bent wat 2 waardes oplevert die je allebei nodig hebt.
Stom voorbeeld (wat uiteraard anders is op te lossen): de buren van een element uit een array terugkrijgen. Voor een gallery in PHP (OOP * MBV bukt :+) had ik een manier nodig om een thumbnail van de volgende en vorige afbeelding te geven, met als enige parameter de bestandsnaam. De oplossing voor dit probleem (2 members maken die bij een getNext en getPrevious allebei gevuld worden) vond ik niet echt netjes, terwijl dat AFAIK de enige manier in Java zou zijn.
Ja, ik had in PHP een array kunnen teruggeven. Ik had er alleen redenen voor om dat niet te doen, geen idee meer welke :)

[ Voor 4% gewijzigd door MBV op 20-11-2005 23:53 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 04:08
momania schreef op zondag 20 november 2005 @ 23:40:
Kan je daar ook een voorbeeld van geven miscshien? Ik heb het zelf nml. nog _nooit_ nodig gehad. :)
Nou ja, de Map.Entry die in de topic start aangehaald werd was naar mijn idee al een goed voorbeeld. Een Map is bij uitstek een container die paren opslaat maar bij gebrek aan een java.util.Pair wordt er zo'n specifieke klasse geïntroduceert, die helemaal niets verschilt van een echte pair.

Als ik dus alle entries opvraag krijg ik een array van Map.Entry's en die kan ik dus niet in andere map implementatie (noem 'm util.soultaker.Map) stoppen omdat ik dan weer mijn eigen pair-object zou gebruiken.

Andere voorbeelden zijn het combineren van een Event met een timestamp, een hostname met een port, enzovoorts. Als je een tijdje in Python ofzo programmeert (waar tuples vrij veel gebruikt worden) dan zie je vanzelf allerlei toepassingen. Kenmerkend is dat het in die gevallen overkill is om er volwaardige klassen van te maken omdat ze toch geen gedrag hebben.

edit:
MBV hierboven haalt ook terecht de deling aan als voorbeeld. Dat is inderdaad ook een mooie.
JKVA schreef op zondag 20 november 2005 @ 23:50:
Zie voorbeeld resultset en statement in mijn vorige post.
Vertel mij dan eens wat een ResultSetMetStatement-entiteit typeert? Wat voor gedrag heeft deze klasse (ie. wat voor methoden geef je 'm, behalve de triviale constructors, getters, setters, comparators en hash codes, die een generieke tupel allemaal al automatisch implementeert)?

Ik kan me er namelijk niet zoveel bij voorstellen. Ik kan me voorstellen dat je methoden hebt voor de statement (checkSyntax() of bindParameter() bijvoorbeeld) en dat je methoden hebt voor de ResultSet (getRowCount(), getColumnType(), etcetera), maar ik zou niet weten wat de combinatie van die twee aan extra mogelijkheden oplevert.

(Ik wil nog benadrukken dat objectgeoriënteerd programmeren begint met objectgeoriënteerd ontwerp; idealiter schrijft je in Java een klasse voor elke entiteit die je bij het ontwerpen bedacht hebt. Dat je in Java ergens een nieuwe klasse voor nodig hebt betekent niet dat het vanuit ontwerpoogpunt een zinnige entiteit is.)

[ Voor 41% gewijzigd door Soultaker op 21-11-2005 00:09 ]


  • momania
  • Registratie: Mei 2000
  • Laatst online: 07:22

momania

iPhone 30! Bam!

Soultaker schreef op maandag 21 november 2005 @ 00:02:
[...]

Nou ja, de Map.Entry die in de topic start aangehaald werd was naar mijn idee al een goed voorbeeld. Een Map is bij uitstek een container die paren opslaat maar bij gebrek aan een java.util.Pair wordt er zo'n specifieke klasse geïntroduceert, die helemaal niets verschilt van een echte pair.

Als ik dus alle entries opvraag krijg ik een array van Map.Entry's en die kan ik dus niet in andere map implementatie (noem 'm util.soultaker.Map) stoppen omdat ik dan weer mijn eigen pair-object zou gebruiken.
Ik zie een map niet als een container met paren. Gewoon als een collectie waarbij elk object opgeslagen wordt onder een unieke key. Gewoon een container waarbij je een object dus snel uit kan halen op basis van een key. Waarbij die key hoogstwaarschijnlijk ook al onderdeel is van het object dat je erin stopt :)

Als ik dus een object nodig heb uit een Map, dan heb ik al een key dus hoef ik die niet weer als resultaat te hebben.

En als ik een eigen Map implementatie zou maken, zou ik toch wel weer gewoon de Map interface implementeren en dan is het dus ook niet moeilijk om alle elementen ineens te kopieren naar je eigen implemenatie :)
Andere voorbeelden zijn het combineren van een Event met een timestamp, een hostname met een port, enzovoorts.
Event en timestamp kan ik even niet volgen. Tenminste, niet waarom je die bij elkaar verpakt zou willen hebben.

Voor hostname en port heb je volgens mij gewoon InternetAdres objecten oid.

Neem je whisky mee, is het te weinig... *zucht*


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 04:08
momania schreef op maandag 21 november 2005 @ 00:16:
Als ik dus een object nodig heb uit een Map, dan heb ik al een key dus hoef ik die niet weer als resultaat te hebben.
Maar als je er door itereert wil je die waarschijnlijk weer wél hebben. ;) (En dat is ook het geval waarin die Map.Entry gebruikt wordt.)
En als ik een eigen Map implementatie zou maken, zou ik toch wel weer gewoon de Map interface implementeren en dan is het dus ook niet moeilijk om alle elementen ineens te kopieren naar je eigen implemenatie :)
Ah ja, het is natuurlijk een interface. Dat scheelt wel weer, inderdaad, maar dan moet ik in mijn eigen Map dus wel die suffe Map.Entry opnieuw implementeren terwijl 'ie exact hetzelfde werkt als elke andere implementatie.
Event en timestamp kan ik even niet volgen. Tenminste, niet waarom je die bij elkaar verpakt zou willen hebben.
Als ik een event loop heb ofzo, dan kan ik me voorstellen dat je behalve de laatset event ook het bijbehorende tijdstip wil hebben. Ik verzon zo maar wat. Een ander voorbeeld: bij een select() call wil ik graag zowel weten hoeveel/welke descriptors readable zijn én hoeveel tijd er verstreken is; twee compleet ongerelateerde waarden.
Voor hostname en port heb je volgens mij gewoon InternetAdres objecten oid.
Een InternetAddress is een e-mailadres en een InetAdress is alleen een hostadres (zonder port dus).

Maar goed, ik wilde helemaal niet zeggen dat al dit soort dingen onmogelijk zijn in Java. Natuurlijk zijn er alternatieven beschikbaar die best werken. Mijn punt is alleen dat er onnodig veel klassen zijn geïntroduceerd omdat Java tuples als fundamenteel type mist.

  • momania
  • Registratie: Mei 2000
  • Laatst online: 07:22

momania

iPhone 30! Bam!

Soultaker schreef op maandag 21 november 2005 @ 00:34:
[...]

Maar als je er door itereert wil je die waarschijnlijk weer wél hebben. ;) (En dat is ook het geval waarin die Map.Entry gebruikt wordt.)
Maar zoals ik al zei: die key is meestal ook onderdeel van het object dat erbij opgeslagen is.

En anders itereer ik gewoon de keySet en haal daarbij per key de value op :P

Neem je whisky mee, is het te weinig... *zucht*


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Ik begin het een beetje een Ja/Nee discussie te vinden.

Mijn mening is dat het zeer veel helpt als je model goed is en doordacht is. Indien je tegen iets heel geks aanloopt, kun je alsnog een dergelijke tuple klasse of container (noem het maar hoe je het wil noemen) maken. Mijn punt uit een aantal posts eerder is alleen dat je zulke dingen zoveel moet vermijden en moet gaan voor een 'logische' en werkbare oplossing.

In sommige gevallen kan het misschien wel logisch of gemakkelijk zijn om een dergelijke tuple of array ofzo terug te geven, maar wat ik wil zeggen is dat je met die dingen op moet letten, want over een maand weet je niet meer wat die functie deed en dan helpt de klassenaam 'Tuple' ook niet veel. Naar mijn idee kun je dan beter het beestje een naam geven door het maken van een nieuwe klasse. In het voorbeeld van die rs en stmt, bijvoorbeeld een functie die ze in 1 regel allebei snel en veilig afsluit. Dat is er namelijk niet (tenminste toen ik dat ding maakte). Ok, het is misschien niet helemaal OO, maar het is wel meteen duidelijk wat het doet en ik noem het zeker geen hack.

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


Verwijderd

Als je een tupel wil returnen maak je toch een class Tupel :+

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Het is overigens ook niet iets bijzonders, een holderklasse, speciaal gemaakt om twee waarden te bevatten. Zie bijvoorbeeld het Spring framework.

http://www.springframewor...servlet/ModelAndView.html

Zeg nou zelf, is dit niet 10 keer duidelijker dan een anonieme tupleklasse die toevallig twee objecten bevat? Iedereen kan in een dergelijk geval lezen dat deze klasse een model en een view bevat.

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


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

momania schreef op maandag 21 november 2005 @ 00:38:
[...]

Maar zoals ik al zei: die key is meestal ook onderdeel van het object dat erbij opgeslagen is.
Nee, dan is het een Set, geen Map
En anders itereer ik gewoon de keySet en haal daarbij per key de value op :P
Nu ben je een beetje allemaal bogus-argumenten aan het verzinnen om maar niet aan de tuple te hoeven :)

Een functie heeft toch ook meerdere parameters? Waarom niet meerdere return-values? Juist, omdat de taal dat gewoon niet toelaat op een handige manier, niet omdat dat vanuit OO standpunt nou beter verantwoord is ofzo.

[ Voor 21% gewijzigd door .oisyn op 21-11-2005 11:19 ]

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

.oisyn schreef op maandag 21 november 2005 @ 11:17:Een functie heeft toch ook meerdere parameters? Waarom niet meerdere return-values? Juist, omdat de taal dat gewoon niet toelaat op een handige manier, niet omdat dat vanuit OO standpunt nou beter verantwoord is ofzo.
Ben ik niet helemaal met je eens. Meerdere return waardes impliceren volgens mij altijd meerdere functies van een methode. In "goede" OO zou een methode 1 functie moeten vervullen over 1 object.

edit:
De mogelijk meerdere parameters mogen wat mij betreft dan ook enkel (direct of indirect) betrekking hebben op 1 object (bijvoorbeeld een substring(int, int)).

[ Voor 16% gewijzigd door Verwijderd op 21-11-2005 11:42 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op maandag 21 november 2005 @ 11:39:
[...]
Ben ik niet helemaal met je eens. Meerdere return waardes impliceren volgens mij altijd meerdere functies van een methode.
En dat is dus helemaal niet waar, een enkele functie kan best meerdere resultaten opleveren, en de voorbeelden in deze draad zijn legio.
De mogelijk meerdere parameters mogen wat mij betreft dan ook enkel (direct of indirect) betrekking hebben op 1 object (bijvoorbeeld een substring(int, int)).
Ik snap niet helemaal wat je bedoelt. Wat zou dan niet goed zijn, volgens jou?

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

.oisyn schreef op maandag 21 november 2005 @ 11:48:
En dat is dus helemaal niet waar, een enkele functie kan best meerdere resultaten opleveren, en de voorbeelden in deze draad zijn legio.

Ik snap niet helemaal wat je bedoelt. Wat zou dan niet goed zijn, volgens jou?
Het resultaat dient dan imho geencapsuleerd te worden in een duidelijk object.

imho is niet goed: een methode met parameters die niet aansluiten bij het te retourneren object.
Dus bijvoorbeeld String replace(String source, String regex, String replace, Integer occurances); lijkt me een voobeeld van een "foute" methode. De integer parameter zegt niets over het te bewerken object String source. Het is een methode die twee functies vervult.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op maandag 21 november 2005 @ 12:03:
[...]

Het resultaat dient dan imho geencapsuleerd te worden in een duidelijk object.
Dat is gewoon een workaround, op dezelfde manier zou je ook met slechts 1 parameter kunnen werken, juist door alle parameters te verpakken in een object. Het punt is dat zo'n object niet echt een zinnig object is; behalve het verpakken van gegevens heeft het geen enkele betekenis.
imho is niet goed: een methode met parameters die niet aansluiten bij het te retourneren object.
Dus bijvoorbeeld String replace(String source, String regex, String replace, Integer occurances); lijkt me een voobeeld van een "foute" methode. De integer parameter zegt niets over het te bewerken object String source. Het is een methode die twee functies vervult.
Nou is me ook een beetje onduidelijk waar die "occurances" überhaupt voor dient ;). Of bedoel je dat als een pass-by-reference variabele, waar een resultaat in komt te staan?

[ Voor 4% gewijzigd door .oisyn op 21-11-2005 12:10 ]

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

.oisyn schreef op maandag 21 november 2005 @ 12:09:
Dat is gewoon een workaround, op dezelfde manier zou je ook met slechts 1 parameter kunnen werken, juist door alle parameters te verpakken in een object. Het punt is dat zo'n object niet echt een zinnig object is; behalve het verpakken van gegevens heeft het geen enkele betekenis.
Waar ligt danh de grens van een nuttige encapsulatie? Vanuit deze flisofie zou je in principe niets hoeven te encapsuleren. Meerdere parameters leveren nou eenmaal een nieuw object.
bv Car create(Chassis chassis, Engine engine, etc....)
.oisyn schreef op maandag 21 november 2005 @ 12:09:Nou is me ook een beetje onduidelijk waar die "occurances" überhaupt voor dient ;). Of bedoel je dat als een pass-by-reference variabele, waar een resultaat in komt te staan?
Het was uiteraard even een snel uit de duim gezogen voorbeeld, doch begrijp je mijn bedoelde werking. Het geeft wel aan dat parameters die niets met het object te maken daar neit horen. De meerdere paramaters dienen altijd voor de bewerking over 1 enkel object.

[ Voor 7% gewijzigd door Verwijderd op 21-11-2005 12:17 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op maandag 21 november 2005 @ 12:16:
[...]
Waar ligt danh de grens van een nuttige encapsulatie? Vanuit deze flisofie zou je in principe niets hoeven te encapsuleren. Meerdere parameters leveren nou eenmaal een nieuw object.
bv Car create(Chassis chassis, Engine engine, etc....)
Klopt, maar een auto is nou eenmaal een zinnige entiteit. Een parseInt functie, die een int retourneert en of het gelukt is, vormt geen zinnige entiteit.
Java:
1
2
3
4
5
6
7
(boolean, int) parseInt(String string);

(boolean succeeded, int result) = parseInt("1235");
if (!succeeded)
    System.out.println("You fucked up!");
else
    System.out.println("The result was " + result);


De combinatie van int en boolean geeft geen zinnige entiteit. Een Tuple<boolean, int> zoals in de topicstart is aangedragen is een aardige workaround voor het probleem, wat in Java helaas nogal wat overhead met zich meebrengt (geheugen alloceren, object aanmaken, object weer garbage collecten), en ook alleen maar omdat meerdere return-values niet ondersteund worden door de taal. Het alternatief is hier natuurlijk het gooien van een exception, maar dat is imho misbruik; het betreft hier geen uitzondering maar gewoon iets dat redelijkerwijs kan gebeuren, en waar je zonder vervelende try-catches op wilt kunnen controleren.

[ Voor 4% gewijzigd door .oisyn op 21-11-2005 12:43 ]

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

.oisyn schreef op maandag 21 november 2005 @ 12:42:
De combinatie van int en boolean geeft geen zinnige entiteit. Een Tuple<boolean, int> zoals in de topicstart is aangedragen is een aardige workaround voor het probleem, wat in Java helaas nogal wat overhead met zich meebrengt (geheugen alloceren, object aanmaken, object weer garbage collecten), en ook alleen maar omdat meerdere return-values niet ondersteund worden door de taal. Het alternatief is hier natuurlijk het gooien van een exception, maar dat is imho misbruik; het betreft hier geen uitzondering maar gewoon iets dat redelijkerwijs kan gebeuren, en waar je zonder vervelende try-catches op wilt kunnen controleren.
Ik ben het met je verhaal eens, maar zoals eerder vermeld niet met de methode. Deze methode vervult nu namelijk twee functies; Het verifieren van de toegestane characters, Het omzetten van characters naar een int. Dit zijn imho dus twee apparte methodes. Een methode parseInt "behoord" dus geldige input om te zetten naar een int.

[ Voor 5% gewijzigd door Verwijderd op 21-11-2005 13:01 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je kunt een int echter niet valideren zonder te 'parsen', als je dat apart gaat nemen dan zit je alleen maar dubbel werk te doen. Nou is die int maar een simpel voorbeeld, als je een hele grammatica wilt controleren dan kun je fouten ook alleen maar ontdekken door juist te gaan parsen. Het heeft zijn eigen data nodig om zichzelf te valideren. Wat jij nu voorstelt is dat het hele -niet zo kostenloze- proces twee keer op exact dezelfde manier doorlopen moet worden, zodat je na de eerste keer weet of het überhaupt gaat lukken, en pas bij de tweede keer je resultaat krijgt (terwijl dat bij de eerste keer al bestond, maar weer weggegooid werd omdat dat immers niet hetgene was wat de functie hoefte te retourneren)

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.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Overigens vind ik een exception wel op z'n plaats hoor hier. Tenminste als het gaat om het parsen van statische configuratie/code files oid; misschien niet als het een interactieve commandline is. Hoewel wij programmeurs natuurlijk weten dat het foutlous compilen eerder de uitzondering is.... exception bij succes? ;)

Verwijderd

@oisyn
Nee niet met je eens. Er treed namelijk geen dubbele validatie op! Het verschil zit hem in de nuance. De parseInt methode gaat er vanuit dat de waarde correct zijn, de validatie doet dat niet. Je leunt dus bij parseInt op andere (onderliggende) excepties. Bottomline is dat je er vanuit gaat dat alles wel goed gaat. Tevens wordt je code minder transparant. Immers validatie kan meer inhouden dan enkel kijken of er numerieke waardes zijn ingevoerd.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ga anders eerst even inlezen over parsers, want je kunt niet valideren zonder te parsen :)

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

.oisyn schreef op maandag 21 november 2005 @ 13:32:
Ga anders eerst even inlezen over parsers, want je kunt niet valideren zonder te parsen :)
Dit heeft niets te maken met wat ik van parsen weet. Het heeft te maken met de nuance in het onderscheidt van de twee processen die je klaarblijkelijk niet herkent.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee, jij begrijpt niet dat, hoewel die nuance er qua concept er wellicht wel is, er het qua code er totaal niet is. Je hebt dus 2 functies die hetzelfde doen, maar een verschillend resultaat opleveren. Dan kun je dat wel in woorden gaan nuanceren, maar in de implementatie van die functies blijft er van die nuance maar weinig over. En dat is het hele punt dat ik 3 posts terug probeerde te maken.

[ Voor 9% gewijzigd door .oisyn op 21-11-2005 14:00 ]

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

Als je zo hardnekkig je standpunt blijft vasthouden prima, dan zijn meerdere return waardes inderdaad wenselijk. En zodra je begrijpt dat het zowel conceptueel als praktisch twee verschillende dingen zijn kun je wel met 1 return waarde toe doen.

En zoals mijn grote vriend Goderie het mooi kan zeggen: "Dikke doei" :)

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Je zou misschien wel eerst er een syntax parser overheen kunnen gooien, die alleen syntax checked en geen semantiek leest. En vervolgens de semantische parser laten gaan, die dan weet dat de syntax goed is. Probleem is dat je semantiek nog steeds fout kan zijn (int overflow bv), en dat de twee routines eigenlijk min of meer hetzelfde doen.

Compilers werken iha met een tokenizer, een parser en een semantics checker oid. De tokenizer maakt brokjes samenhangende karakters (bv. integer-constant), de parser combineert deze brokjes samen mbv de gramatica/syntax en geeft eventuele errors in de syntax. De output is een abstract syntax tree waar een sematische validatie overheen gaat. Op het moment dat die draait ben je al los van je source file, en staat alles gestructureerd in geheugen.

Ik denk dat Mark daar een beetje mee in de war is. Zowel de tokenizer als parser (die in kleine projecten samengevoegd worden) lezen text string input en retourneren een andere versie hiervan. Als dit fout gaat, dan moet je een error kunnen retourneren. Overigens is er een simpel truckje door pointers naar nieuwe objecten te retourneren, en een null-pointer bij een fout te sturen. Vervolgens is er een extra functie getLastError() die je verteld wat er als laatst is fout gegaan. Dit wordt veel gebruikt in de praktijk, maar is een beetje een C iets. Zie windows.

Vaak wil je na een fout in de parser verder parsen. Bepaalde types parsers ondersteunen dit door net zo lang door te lezen totdat ze weer in consistente staat komen. Een exception is dan lastig als fout indicatie, omdat je niet zonder meer door kan gaan waar je was. Maar het is wel bruikbaar te maken door een extra routine te maken die de parser in consitente staat terug brengt, en dan het parsen opnieuw te starten vanaf daar.

Als je taal geen null-pointers ondersteunt, dan kan je een extra functie bool errorOccured() maken die je na elke actie moet aanroepen. Erg vervelend... zie OpenGL :P Hoewel je anders ook steeds op een null pointer moet checken. Daarom ben ik toch nog steeds voor exceptions. Een parse error is een exceptioneel iets. Maar stel dat je een functie hebt die heel vaak failure report, dan is een exception geen optie. Feit blijft dat je soms zowel een error indicatie als een resultaat moet retourneren. De meest natuurlijke manier is met een tuple/pair. Al die andere manieren zijn slechts 'hacks' om dit min of meer te bereiken in talen zonder ondersteuning. Met de null pointer codeer je twee delen informatie in een entiteit, met de error functies als je het tuple gewoon globaal op in geheugen ipv op de stack (ook nog niet thread safe...)

Mooi voorbeeld is trouwens het pollen van een sensor die updates stuurt. De sensor heeft of geen nieuwe data beschikbaar, of hij stuurt je de nieuwe data. Hier kan je niet eerst pollen of er data is, en dan opnieuw om de data te halen. In dit geval, met deze sensor, moet je twee return waardes accepteren.

[ Voor 6% gewijzigd door Zoijar op 21-11-2005 14:41 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op maandag 21 november 2005 @ 14:15:
Als je zo hardnekkig je standpunt blijft vasthouden prima, dan zijn meerdere return waardes inderdaad wenselijk. En zodra je begrijpt dat het zowel conceptueel als praktisch twee verschillende dingen zijn kun je wel met 1 return waarde toe doen.
Cursus begrijpend lezen nodig? Lekker makkelijk hoor, zo :)
Zoijar schreef op maandag 21 november 2005 @ 14:30:
Feit blijft dat je soms zowel een error indicatie als een resultaat moet retourneren. De meest natuurlijke manier is met een tuple/pair. Al die andere manieren zijn slechts 'hacks' om dit min of meer te bereiken in talen zonder ondersteuning.
Juistem, dat was het hele verhaal dat ik duidelijk probeerde te maken, dank je :)

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

.oisyn schreef op maandag 21 november 2005 @ 14:54:
Cursus begrijpend lezen nodig? Lekker makkelijk hoor, zo :)
Zullen we samen inschrijven O+

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

Confusion

Fallen from grace

Soultaker schreef op zondag 20 november 2005 @ 20:28:
Op die manier is het systeem dus gesloten en kan een applicatie geen ongeldige pointer maken en hoeft de virtual machine daar dus ook nooit meer op te controleren. Die controleerbaarheid is de reden dat Java beperkingen oplegt aan operaties op pointers (of references, of hoe je ze wil noemen), niet dat die operaties te ingewikkeld zouden zijn voor de programmeur ofzoiets.
In je uitleg zie ik eigenlijk geen reden om geen 'echte' pointers aan de taal toe te voegen. Je kan toch prima de JVM al zijn dingen laten doen, terwijl de pointer operaties geheel voor verantwoording van de programmeur zijn? Als ik gewoon een pointer kan maken, met één of andere malloc-achtige functie geheugen kan reserveren en daar spul in kan stoppen, dan heeft de JVM van dat geheugen af te blijven. Verder moet de programmeur maar zorgen dat de verdere werking van de JVM zijn programma niet ondermijnd. Veiligheidsoverwegingen idem dito: dat is dan, net als elders, geheel de verantwoording van de programmeur.

Komt wat je zegt niet neer op: Java is veilig en heeft een handige GC en met pointers zou dat niet zo zijn. Dat is dat toch hetzelfde als zeggen: programmeurs die pointers gebruiken maken onveilige programma's en maken fouten met geheugenoperaties. Een programmeur zou toch prima zo met 'echte' pointers om kunnen gaan dat de JVM zich nergens zorgen over hoefde te maken, zonder dat het onveiliger wordt dan pakweg C?

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


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Confusion schreef op maandag 21 november 2005 @ 22:01:
[...]

In je uitleg zie ik eigenlijk geen reden om geen 'echte' pointers aan de taal toe te voegen. Je kan toch prima de JVM al zijn dingen laten doen, terwijl de pointer operaties geheel voor verantwoording van de programmeur zijn? Als ik gewoon een pointer kan maken, met één of andere malloc-achtige functie geheugen kan reserveren en daar spul in kan stoppen, dan heeft de JVM van dat geheugen af te blijven. Verder moet de programmeur maar zorgen dat de verdere werking van de JVM zijn programma niet ondermijnd. Veiligheidsoverwegingen idem dito: dat is dan, net als elders, geheel de verantwoording van de programmeur.

Komt wat je zegt niet neer op: Java is veilig en heeft een handige GC en met pointers zou dat niet zo zijn. Dat is dat toch hetzelfde als zeggen: programmeurs die pointers gebruiken maken onveilige programma's en maken fouten met geheugenoperaties. Een programmeur zou toch prima zo met 'echte' pointers om kunnen gaan dat de JVM zich nergens zorgen over hoefde te maken, zonder dat het onveiliger wordt dan pakweg C?
JVM moet remote code kunnen draaien, de veiligheid ligt dan bij een andere programmeur. Zou jij op je systeem een unrestricted java applet laten draaien? :)

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 04:08
Confusion schreef op maandag 21 november 2005 @ 22:01:
Je kan toch prima de JVM al zijn dingen laten doen, terwijl de pointer operaties geheel voor verantwoording van de programmeur zijn? [..] Veiligheidsoverwegingen idem dito: dat is dan, net als elders, geheel de verantwoording van de programmeur.
Dan kan een foutief programma dus het hele proces kapen (middels een buffer overflow ofzo). Dan is de security dus verdwenen en kun je geen dingen als Java applets of andere in je browser meer laden, of andere componenten. Dat Java-applicaties in een beveiligde omgeving draaien is juist hét voordeel van het Java platform; als je dat opgeeft hou je een trage versie van C over.
Komt wat je zegt niet neer op: Java is veilig en heeft een handige GC en met pointers zou dat niet zo zijn. Dat is dat toch hetzelfde als zeggen: programmeurs die pointers gebruiken maken onveilige programma's en maken fouten met geheugenoperaties. Een programmeur zou toch prima zo met 'echte' pointers om kunnen gaan dat de JVM zich nergens zorgen over hoefde te maken, zonder dat het onveiliger wordt dan pakweg C?
Het gaat er om dat een programmeur fouten kan maken. Dan gaat het ook gebeuren. Het wordt niet onveiliger dan C, maar net zo onveilig.

Een recent voorbeeld was een bug in Windows in de DLL om PNG-files mee te laden waar een buffer overflow in zat. Alle applicaties die die DLL gebruikten waren in één klap lek. Als het een Java-component was geweest in plaats van een 'ouderwetse' library, had dat niet kunnen gebeuren, omdat zo'n component het proces waarin het draait niet kan verknoeien.

Het is ook niet voor niets dat Microsoft's .NET op eenzelfde manier in elkaar steekt: de verifiability van applicaties is één van de belangrijkste redenen waarom Microsoft zo'n platform wil hebben. (Portability is van ondergeschikt belang: C code is ook portable en Microsoft ontwikkelt .NET toch alleen maar voor Windows.) Die eigenschap is dus echt essentieel aan het ontwerp en die zou je verpesten met C-achtige pointers.

[ Voor 13% gewijzigd door Soultaker op 21-11-2005 22:44 ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Soultaker schreef op maandag 21 november 2005 @ 22:38:
Het is ook niet voor niets dat Microsoft's .NET op eenzelfde manier in elkaar steekt: de verifiability van applicaties is één van de belangrijkste redenen waarom Microsoft zo'n platform wil hebben. (Portability is van ondergeschikt belang: C code is ook portable en Microsoft ontwikkelt .NET toch alleen maar voor Windows.) Die eigenschap is dus echt essentieel aan het ontwerp en die zou je verpesten met C-achtige pointers.
Eindelijk een goed argument voor Java ;) Ben het geheel met je eens.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Maar al met al geen reden om geen pass-by-references te ondersteunen ;)

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.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Uiteraard niet, laten we het niet te gek maken ;)

  • Macros
  • Registratie: Februari 2000
  • Laatst online: 21-11 11:06

Macros

I'm watching...

Topicstarter
Ik ben al blij dat Java geen default pass-by-copy gebruikt zoals PHP (vroeger) had. Dat was pas afschuwelijk!

"Beauty is the ultimate defence against complexity." David Gelernter


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

Confusion

Fallen from grace

Soultaker schreef op maandag 21 november 2005 @ 22:38:
Dan kan een foutief programma dus het hele proces kapen (middels een buffer overflow ofzo). Dan is de security dus verdwenen en kun je geen dingen als Java applets of andere in je browser meer laden, of andere componenten. Dat Java-applicaties in een beveiligde omgeving draaien is juist hét voordeel van het Java platform; als je dat opgeeft hou je een trage versie van C over.
Dat geldt alleen voor applets. Je kan het gebruik van het extra taalelement daar verbieden. Voor server- en andere applicaties zou je Java hebben, met de mogelijkheid jezelf, net als in C, desastreus in de voet te schieten. Als je er dan alsnog voor kiest om zo'n taalelement weg te laten, dan ligt dat ergens anders aan, net als het weglaten van de goto statement.
Het is ook niet voor niets dat Microsoft's .NET op eenzelfde manier in elkaar steekt: de verifiability van applicaties is één van de belangrijkste redenen waarom Microsoft zo'n platform wil hebben. (Portability is van ondergeschikt belang: C code is ook portable en Microsoft ontwikkelt .NET toch alleen maar voor Windows.) Die eigenschap is dus echt essentieel aan het ontwerp en die zou je verpesten met C-achtige pointers.
Dus pointers zitten er niet in, omdat je anders geen verifiable applicatie kan bouwen, omdat programmeurs daar te lomp voor zijn. Laten we wel wezen: briljante, alles voorziende programmeurs zouden altijd werkende, veilige programmas afleveren en zouden zo'n platform niet nodig hebben. Deze ontwerpfilosofie is ontstaan, is nodig, omdat telkens weer blijkt dat ze dat niet kunnen.

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


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Confusion schreef op dinsdag 22 november 2005 @ 06:59:
[...]

Dat geldt alleen voor applets. Je kan het gebruik van het extra taalelement daar verbieden. Voor server- en andere applicaties zou je Java hebben, met de mogelijkheid jezelf, net als in C, desastreus in de voet te schieten. Als je er dan alsnog voor kiest om zo'n taalelement weg te laten, dan ligt dat ergens anders aan, net als het weglaten van de goto statement.
Het weglaten van het goto statement heeft daar weinig mee te maken, en volgens mij kun je met java bytecode gewoon jumpen. Daarnaast zijn applets heus niet de enige omgeving waarin secure gewerkt moet worden; met andere typen addins wil je dat ook, en ook op een hosting server kan ik me voorstellen dat het fijner is als je gebruikers de boel niet desastreus over de zeik kunnen helpen.

Let wel, Java heeft weldegelijk de mogelijkheid tot "unsafe" code. Niet zo uitgebreid als .Net dat heeft geloof ik, maar dingen als java.nio zijn volgens mij unchecked om het zo sneller te laten werken. Ook was er in een van de beta's nog een lek waarmee je random geheugen kon touchen mbv read en write functies. En die class is daar uiteraard voor een reden, het was alleen niet de bedoeling dat ie zo makkelijk aanspreekbaar was.
Dus pointers zitten er niet in, omdat je anders geen verifiable applicatie kan bouwen, omdat programmeurs daar te lomp voor zijn. Laten we wel wezen: briljante, alles voorziende programmeurs zouden altijd werkende, veilige programmas afleveren en zouden zo'n platform niet nodig hebben. Deze ontwerpfilosofie is ontstaan, is nodig, omdat telkens weer blijkt dat ze dat niet kunnen.
Ik denk dat dat niet de enige reden is waarom er geen pointers in zitten. Java is in essentie platform onafhankelijk, net als de C++ specificatie dat is. De C++ specificatie zegt dat pointer arithmetic undefined is voor pointers die niet uit dezelfde allocatie komen, omdat het onderliggende systeem weleens een heel ander geheugenmodel kan gebruiken dan het flat memory model. In zo'n geheugenmodel kun je niet zomaar met pointers werken, tenzij je met een pointer niets anders kan dan wijzen naar een voorgedefinieerde variabele.

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: 04:08
Confusion schreef op dinsdag 22 november 2005 @ 06:59:
Dat geldt alleen voor applets. Je kan het gebruik van het extra taalelement daar verbieden. Voor server- en andere applicaties zou je Java hebben, met de mogelijkheid jezelf, net als in C, desastreus in de voet te schieten. Als je er dan alsnog voor kiest om zo'n taalelement weg te laten, dan ligt dat ergens anders aan, net als het weglaten van de goto statement.
[...]
Dus pointers zitten er niet in, omdat je anders geen verifiable applicatie kan bouwen, omdat programmeurs daar te lomp voor zijn.
Veriability is niet zomaar een softe term die ik hier verzin; het is de eigenschap dat het mogelijk is om aan de hand van de byte code van een applicatie te verifiëren dat een applicatie aan alle geldende constraints voldoet (niet buiten je stack frame lezen, geen private variabelen benaderen, en zo nog een heleboel meer).

Er zit dan ook een verifier in de JVM (en in .NET) die byte code controleert alvorens die uit te voeren. Die garandeert dat een applicatie zich aan de regels houdt. Je kunt van te voren niet controleren of pointeroperaties aan die eisen voldoen dus als je die toe zou staan in je byte code, dan zou je de verificatie at runtime moeten doen, wat veel te kostbaar is.

In een normaal proces heb je dan ook helemaal geen verificatie; er wordt hardwarematig gegarandeerd dat je niet buiten je process space kunt lezen of schrijven en verder mag je prutsen wat je wil.

Merk op dat ik het in dit verhaal nog helemaal niet over programmeertalen heb gehad. Die komen daarna pas. Java ondersteunt geen C-achtige pointers omdat het platform dat niet ondersteunt: als je het in Java zou inbouwen zou je niet naar JVM bytecode kunnen compileren en dan had Sun dus de JVM véél inefficiënter moeten opbouwen (namelijk elke pointer reference at runtime controleren). (Java zou trouwens best goto kunnen implementeren, maar alleen binnen een stack frame; eigenlijk net zo als C++.)

Dus samenvattend: je kunt óók geen pointers toestaan in andere applicaties en dat controle van pointeroperaties inefficiënt is heeft niets met lompe programmeurs te maken (hoewel die er natuurlijk veel zijn en het geen slecht idee is om daar vanuit te gaan als je een programmeertaal/platform ontwerpt).
.oisyn schreef op dinsdag 22 november 2005 @ 11:38:
Let wel, Java heeft weldegelijk de mogelijkheid tot "unsafe" code. Niet zo uitgebreid als .Net dat heeft geloof ik, maar dingen als java.nio zijn volgens mij unchecked om het zo sneller te laten werken.
Afaik heb je in Java de keuze tussen óf pure Java (eventueel met wat rare JVM hacks zoals weak references) óf je moet de Java Native Interface gebruiken en dan ook gelijk in C coden. Bij .NET heb je nog C++.NET als tussenvorm, die wel de features van native C++ ondersteund en ook wat extensies heeft om met .NET te werken.
Ook was er in een van de beta's nog een lek waarmee je random geheugen kon touchen mbv read en write functies. En die class is daar uiteraard voor een reden, het was alleen niet de bedoeling dat ie zo makkelijk aanspreekbaar was.
Sowieso zaten er in oude Java versies nogal wat bugs in de verifier, waardoor je jezelf extra permissies kon toekennen als je handige bytecode schreef. Ik geloof dat .NET een stuk minder last heeft (gehad) van dat soort bugs.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op dinsdag 22 november 2005 @ 13:25:
Afaik heb je in Java de keuze tussen óf pure Java (eventueel met wat rare JVM hacks zoals weak references) óf je moet de Java Native Interface gebruiken en dan ook gelijk in C coden.
sun.misc.Unsafe ;)
Bij .NET heb je nog C++.NET als tussenvorm, die wel de features van native C++ ondersteund en ook wat extensies heeft om met .NET te werken.
In C# kun je ook gewoon met pointers werken hoor :). Het platform staat het ook gewoon toe, maar dus wel alleen in unsafe gemarkeerde blokken.

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.


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

Confusion

Fallen from grace

Soultaker schreef op dinsdag 22 november 2005 @ 13:25:
Veriability is niet zomaar een softe term die ik hier verzin; het is de eigenschap dat het mogelijk is om aan de hand van de byte code van een applicatie te verifiëren dat een applicatie aan alle geldende constraints voldoet (niet buiten je stack frame lezen, geen private variabelen benaderen, en zo nog een heleboel meer).
Op dit moment ben je al voorbij aan het punt dat ik wil maken. Waarom is er de wens applicaties te verifieren? Omdat programmeurs programmas schrijven die zich niet naar behoren gedragen. Als ze altijd op bovenmenselijke wijze hun werk deden, dan was die wens er eenvoudigweg niet*. Dan had nooit iemand bedacht dat er verifiable applicaties moesten komen. Toen het Java team dat wel bedacht, toen moesten ze dus automagisch garanderen dat het programma geen fouten met de geheugentoegang zou maken. Om de redenen die jij gegeven hebt betekent dat dat ze programmeurs niet langer met pointers konden laten spelen.

Ik bedoel dus zeker niet dat de ontwerpers bedachten: programmeurs zijn prutsers en pointers zuigen, laten we daar eens iets op verzinnen**. Maar de reden dat ze uberhaupt een nieuw platform met bepaalde eigenschappen gingen ontwerpen, is dat er problemen opgelost moesten worden. Een van die problemen was dat bestaande applicaties de geheugenintegriteit niet respecteerden. Het probleem was niet dat de applicaties geen geheugenintegriteit kon garanderen: als je iets altijd vertoond, dan interesseert het niemand of je het kan garanderen. Pointers moesten wijken voor de garantie van geheugenintegriteit, omdat mensen die pointers gebruiken geheugenintegriteit niet kunnen garanderen.

* Dit is kort door de bocht; er zijn natuurlijk meerdere redenen en het geheel grijpt in elkaar
** Mijn reactie op -NMe- was onduidelijk

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


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Confusion schreef op dinsdag 22 november 2005 @ 14:12:
[...]

Op dit moment ben je al voorbij aan het punt dat ik wil maken.
Wat ìs het punt dat je wil maken? Mensen maken fouten, iedereen weet dat. Ik zie de relevantie met deze topic eerlijk gezegd niet :)

Overigens, nogmaals, pointers hoeven an sich niet unsafe te zijn. Zolang je het adres maar niet handmatig aan mag passen, past het prima in het design van de JVM, zonder de security te compromizen. Uiteraard mag zo'n pointer niet wijzen naar een variabele op de stack, aangezien die buiten scope kan gaan, maar verder is dat best goed te doen en zonder runtime checks.

[ Voor 38% gewijzigd door .oisyn op 22-11-2005 14:26 ]

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: 04:08
Confusion schreef op dinsdag 22 november 2005 @ 14:12:
Op dit moment ben je al voorbij aan het punt dat ik wil maken. Waarom is er de wens applicaties te verifieren? Omdat programmeurs programmas schrijven die zich niet naar behoren gedragen. Als ze altijd op bovenmenselijke wijze hun werk deden, dan was die wens er eenvoudigweg niet.
Accoord. Maar de reden om ze uit Java-de-taal te laten is dus wel degelijk dat de taal gecompileerd moet worden naar Java-het-platform die het niet ondersteunt, en Java-het-platform ondersteund het niet omdat het niet te verenigen valt met de sterke garanties die het platform levert (als je tenminste nog een beetje performance wil overhouden). Ik denk dat we het daar wel over eens zijn.
Mijn reactie op -NMe- was onduidelijk
Inderdaad. :P
.oisyn schreef op dinsdag 22 november 2005 @ 14:21:
Overigens, nogmaals, pointers hoeven an sich niet unsafe te zijn. Zolang je het adres maar niet handmatig aan mag passen, past het prima in het design van de JVM, zonder de security te compromizen. Uiteraard mag zo'n pointer niet wijzen naar een variabele op de stack, aangezien die buiten scope kan gaan, maar verder is dat best goed te doen en zonder runtime checks.
Maar dan kom je weer terecht in de discussie van 'waarin verschilt een pointer nu van een reference', wat dus vooral een definitiekwestie is. Of bedoel je dat je best dingen als een pointer zou mogen maken naar, zeg, het midden van een array of een primitive attribute van een object?

De JVM ondersteunt dat nu natuurlijk niet, maar het is wel mogelijk. Aan de andere kant is het lastig omdat je bounds checking dan anders moet én je garbage collector er rekening mee moet houden dat een applicatie niet alleen pointers naar het begin, maar ook in het midden van een object kunnen hebben.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op dinsdag 22 november 2005 @ 14:34:
Maar dan kom je weer terecht in de discussie van 'waarin verschilt een pointer nu van een reference', wat dus vooral een definitiekwestie is. Of bedoel je dat je best dingen als een pointer zou mogen maken naar, zeg, het midden van een array of een primitive attribute van een object?
Dat ja, gewoon een entiteit dat je naar een bestaand iets kunt laten wijzen (dus idd een attribuut van een object of een element uit een array), en dat dat (en het dereferencen natuurlijk) het enige is wat je ermee kan, dus niet rekenen en ook niet converteren naar een int en weer terug.
Aan de andere kant is het lastig omdat je bounds checking dan anders moet
Waarom? Je hoeft die array bounds alleen maar te checken op het moment dat je zo'n pointer laat wijzen naar een element uit de array. En arrays zijn -wat lengte betreft- immutable, dus je hebt ook niet het risico dat een pointer ongeldig wordt op het moment dat de array kleiner wordt.
én je garbage collector er rekening mee moet houden dat een applicatie niet alleen pointers naar het begin, maar ook in het midden van een object kunnen hebben.
Je zult zo'n pointer toch moeten implementeren als een handle+offset, aangezien objecten rond geschoven kunnen worden in het geheugen, waardoor een hard geheugenadres sowieso al niet voldoet. En dan is het dus niets meer dan een al bestaande reference, met nog een beetje extra informatie. Uiteraard zal de VM hierop aangepast moeten worden aangezien er niets is dat dit faciliteert :)

[ Voor 8% gewijzigd door .oisyn op 22-11-2005 15:08 ]

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.


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

Confusion

Fallen from grace

.oisyn schreef op dinsdag 22 november 2005 @ 14:21:
Wat ìs het punt dat je wil maken? Mensen maken fouten, iedereen weet dat. Ik zie de relevantie met deze topic eerlijk gezegd niet :)
Ehmmm ja, ik ben een beetje afgedwaald. Indirect was mijn punt dat het niet mogelijk maken van meerdere return values ook heel goed een bewuste ontwerpoverweging kan zijn. Dus ongeacht of het zou kunnen (zoals blijkbaar in Nice), moet je het misschien helemaal niet willen. Het betekent dat de cohesie van de functie vrij laag zal zijn. Is er niet altijd een goede oplossing zonder meerdere return values?
Overigens, nogmaals, pointers hoeven an sich niet unsafe te zijn.
Oh nee, ik ben ook niet bang voor pointers; leuke dingen ;).

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


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Confusion schreef op woensdag 23 november 2005 @ 09:08:
[...]

Ehmmm ja, ik ben een beetje afgedwaald. Indirect was mijn punt dat het niet mogelijk maken van meerdere return values ook heel goed een bewuste ontwerpoverweging kan zijn. Dus ongeacht of het zou kunnen (zoals blijkbaar in Nice), moet je het misschien helemaal niet willen. Het betekent dat de cohesie van de functie vrij laag zal zijn. Is er niet altijd een goede oplossing zonder meerdere return values?
Nee. In sommige gevallen ben je gewoon meer info nodig dan in een 'simpele' return waarde post. Ik moet toegeven dat me dit nog niet vaak overkomen is, en als dit wel het geval is, dan maak ik meestal wel een overkoepeld object. Soms geeft dit wat ruis aangezien het object zelf niet bijster interessant is, maar voor die enkele keer kan ik ermee leven. Dus zijn meerdere return waardes nuttig? Ja. Moet het in een mainstream taal komen? don`t care.

[ Voor 5% gewijzigd door Alarmnummer op 23-11-2005 09:21 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Tot slot nog even een mooie C++ oplossing:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
Tuple<int, float> foo()
{
    return make_tuple(3, 4.54f);
}

int main()
{
    int i;
    float f;
    assign_tuple(i, f) = foo();

    std::cout << i << ", " << f << std::endl;
}


Een mogelijke implementatie zou kunnen zijn:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
template<class T1, class T2 = void, class T3 = void, class T4 = void, class T5 = void /*enzovoorts voor 6..n*/>
struct Tuple;

// specialization voor 1 parameter
template<class T1> struct Tuple<T1>
{
    T1 first;

    Tuple() : first() { }
    Tuple(T1 t1) : first(t1) { }
};

// specialization voor 2 parameters
template<class T1, class T2> struct Tuple<T1, T2>
{
    T1 first;
    T2 second;

    Tuple() : first(), second() { }
    Tuple(T1 t1, T2 t2) : first(t1), second(t2) { }
};
// enzovoorts voor 3..n


// specializations voor 1 reference parameter
template<class T1> struct Tuple<T1&>
{
    T1 * first;

    Tuple(T1 & t1) : first(&t1) { }
    Tuple& operator = (const Tuple<T1> & t) { *first = t.first; return *this; }
};

// specializations voor 2 reference parameters
template<class T1, class T2> struct Tuple<T1&, T2&>
{
    T1 * first;
    T2 * second;

    Tuple(T1 & t1, T2 & t2) : first(&t1), second(&t2) { }
    Tuple& operator = (const Tuple<T1, T2> & t) { *first = t.first; *second = t.second; return *this; }
};
// enzovoorts voor 3..n


// tuple utility functies
template<class T1> Tuple<T1> make_tuple(const T1 & t1)
{
    return Tuple<T1>(t1);
}

template<class T1, class T2> Tuple<T1, T2> make_tuple(const T1 & t1, const T2 & t2)
{
    return Tuple<T1, T2>(t1, t2);
}
// enzovoorts voor 3..n


template<class T1> Tuple<T1&> assign_tuple(T1 & t1)
{
    return Tuple<T1&>(t1);
}

template<class T1, class T2> Tuple<T1&, T2&> assign_tuple(T1 & t1, T2 & t2)
{
    return Tuple<T1&, T2&>(t1, t2);
}
// enzovoorts voor 3..n

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.

Pagina: 1