[.NET] New language features in C#

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

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:54
Vandaag las ik op GotDotNet volgend artikel:

New language features

Hier staat dat er in de volgende 'major' release van C# vier belangrijke nieuwe features in C# komen:

- Generics
- Iterators
- Anonymous methods
- Partial types

De eerste 2 punten juich ik toe, de 2 laatste vind ik eigenlijk maar niets. Die 2 laatste punten (Anonymous methods en Partial types) vind ik eigenlijk niets meer dan wat gadgets en ik ben niet van plan om die 2 'gadgets' te gaan gebruiken; ik denk dat het gebruik ervan bijdraagt tot 'onduidelijke' code.
Generics is een feature waar men lang (relatief dan) op gewacht heeft, en zijn zeer handig. De nieuwe iterator - constructies vind ik ook veel duidelijker dan hetgeen we nu moeten schrijven.

https://fgheysels.github.io/


  • Orphix
  • Registratie: Februari 2000
  • Niet online
De generics vind ik wel handig. Het is gewoon een extra constraint die je toe kan passen en geeft de compiler kans daar handige truukjes mee te doen. Het dwingt je ook iets netter te programmeren. Nou moet ik zeggen dat generics handig kunnen zijn, maar dat ik het niet echt als een groot gemis heb gezien.

De iterators wijzen gelukkig op een nieuwe methode om de foreach construct in je eigen classes te ondersteunen en geen nieuwe iteratie methode (foreach vind ik nml heel lekker werken). Het was inderdaad wat omslachtig, maar de nieuwe methode vind ik niet echt heel fraai. Via Yield in een methode kan je elke keer een nieuw object teruggeven. Er wordt ook opeens geen return meer gebruikt?
Om voor dit probleem nou een compleet nieuw keyword toe te voegen die effectief de werking van een methode drastisch veranderd is misschien niet helemaal netjes. Ik had liever iets gezien wat meer volgens het traditionele paradigma werkt. Maar aan de andere kant, ik heb er als client/gebruiker van een lijst geen notie van, dus what the heck :Y)

De anonymous methods vind ik persoonlijk wel handig. In Java gebruik ik ze vrij vaak en vooral voor simple eventhandling (mouse-click die direct 1 functie aanroept) is het erg handig en bovendien ook leesbaarder.

De partial types ... tja ... snap het nut niet echt :D Een class maken en vervolgens 100 regels verderop (of in een ander bestand) daarmee verder gaan? Nah ik vind het niet echt netjes en ben bovendien bang dat dit misbruikt gaat worden voor gevallen waar inheritance misschien beter op z'n plek was. Maar verder heb ik geen ervaring met partial types dus misschien zie ik iets essentieels over het hoofd.

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:54
Orphix schreef op 13 november 2002 @ 19:47:
De generics vind ik wel handig. Het is gewoon een extra constraint die je toe kan passen en geeft de compiler kans daar handige truukjes mee te doen. Het dwingt je ook iets netter te programmeren. Nou moet ik zeggen dat generics handig kunnen zijn, maar dat ik het niet echt als een groot gemis heb gezien.
Idd, en je hoeft niet telkens te gaan casten enzo als je objects uit een ArrayList haalt.
De iterators wijzen gelukkig op een nieuwe methode om de foreach construct in je eigen classes te ondersteunen en geen nieuwe iteratie methode (foreach vind ik nml heel lekker werken). Het was inderdaad wat omslachtig, maar de nieuwe methode vind ik niet echt heel fraai. Via Yield in een methode kan je elke keer een nieuw object teruggeven. Er wordt ook opeens geen return meer gebruikt?
Hmm... Hier heb je wel gelijk... Ik had er nog niet aan gedacht, aan dat return keyword. :z
Om voor dit probleem nou een compleet nieuw keyword toe te voegen die effectief de werking van een methode drastisch veranderd is misschien niet helemaal netjes. Ik had liever iets gezien wat meer volgens het traditionele paradigma werkt. Maar aan de andere kant, ik heb er als client/gebruiker van een lijst geen notie van, dus what the heck :Y)
Das dan ook wel weer waar.... Er zal wel een of andere vage reden zijn dat die return niet voldeed....
Het valt mij nu eigenlijk net in.... Een return statement zorgt er toch voor dat de method beëindigd wordt? Daarom misschien....
De anonymous methods vind ik persoonlijk wel handig. In Java gebruik ik ze vrij vaak en vooral voor simple eventhandling (mouse-click die direct 1 functie aanroept) is het erg handig en bovendien ook leesbaarder.
Mwah, ik zie er niet echt het nut/handigheid van in enzo....
De partial types ... tja ... snap het nut niet echt :D Een class maken en vervolgens 100 regels verderop (of in een ander bestand) daarmee verder gaan? Nah ik vind het niet echt netjes en ben bovendien bang dat dit misbruikt gaat worden voor gevallen waar inheritance misschien beter op z'n plek was. Maar verder heb ik geen ervaring met partial types dus misschien zie ik iets essentieels over het hoofd.

Ik moet dat stuk over partial types nog eens goed lezen, maar ik zie niet echt het verband/relatie met inheritance in. Ik denk niet dat je beide kunt vergelijken. Ik dacht eerder dat die partial types te maken hadden met het splitsen van eenzelfde class over meerdere bestanden... * whoami moet dat artikel nog maar eens doornemen.

https://fgheysels.github.io/


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Orphix schreef op 13 November 2002 @ 19:47:
De iterators wijzen gelukkig op een nieuwe methode om de foreach construct in je eigen classes te ondersteunen en geen nieuwe iteratie methode (foreach vind ik nml heel lekker werken). Het was inderdaad wat omslachtig, maar de nieuwe methode vind ik niet echt heel fraai. Via Yield in een methode kan je elke keer een nieuw object teruggeven. Er wordt ook opeens geen return meer gebruikt?
Om voor dit probleem nou een compleet nieuw keyword toe te voegen die effectief de werking van een methode drastisch veranderd is misschien niet helemaal netjes. Ik had liever iets gezien wat meer volgens het traditionele paradigma werkt. Maar aan de andere kant, ik heb er als client/gebruiker van een lijst geen notie van, dus what the heck :Y)
De yield-manier zorgt er juist voor dat je zelf niet meer hoeft bij te houden waar in de 'lijst' je zit, waardoor je zoiets kunt doen (niet echt een nuttige toepassing, maar het gaat om het idee):
C++:
1
2
3
4
5
6
// waarom werkt code="C#" niet :S
public object foreach() {
    yield("eerste item");
    yield("tweede item");
    yield("derde item");
}
Wat dus aanzienlijk aan code scheelt :9~ :)

Wat betreft de anonymous methods en de partial klassen bent ik het met Orphix eens: de eerste lijken me wel handig (scheelt weer code :)), en van de tweede zie ik het nut niet in.

Ohja, generics zijn imo eigenlijk onmisbaar voor een OO taal :P

[ Voor 0% gewijzigd door marcusk op 13-11-2002 20:17 . Reden: object type erbij ]


Verwijderd

Lees/typ ik nou zo langzaam of zijn jullie nou zo snel? (Toen ik begon met lezen stonden er nog geen reacties en inmiddels al 3!

Jammer dat de Generics en Iterators nog niet in de Everett-versie, maar pas in de Yukon-versie komen (waarvan de release-datum volgens mij nog niet eens bekend is?)...
/me is het wat die 2 betreft volledig met whoami eens.
whoami schreef op 13 november 2002 @ 19:54:
Ik dacht eerder dat die partial types te maken hadden met het splitsen van eenzelfde class over meerdere bestanden...
Ja, zo had ik 't idd ook gelezen... Dat zou handig kunnen zijn, als je later ineens denkt van: oja, w8 ff... dit moest ook nog in de class erbij... ;)
Zoals het beschreven staat in 't document, zou 't vooral handig zijn bij hele grote class-files, die anders misschien te onoverzichtelijk zouden worden. Dus ok; ik zal 't niet zo snel gebruiken (*), maar echt schokkend vind ik 't ook niet.
offtopic:
Gebruiken jullie altijd maar 1 class-file per class?
marcusk schreef op 13 november 2002 @ 19:55:
Ohja, generics zijn imo eigenlijk onmisbaar voor een OO taal :P
Vind ik ook. Ik snap echt niet waarom dat er nog niet in zit. :)

Die anonymous methods vond ik juist 1 van de mindere dingen in Java... ;) Voor korte methods zou 't handig kunnen zijn, maar waarom definieer je er dan niet gewoon ff een method voor? Zeker voor het terug kunnen vinden van code, lijkt 't me niet zo praktisch. Of zouden die wel ook gewoon in de combo gezet worden? Ik zie daar dus niet echt de voordelen van, maar eerder nadelen...

(*) als een class te groot wordt, heb je er nml. IMHO niet goed genoeg over naged8

  • Orphix
  • Registratie: Februari 2000
  • Niet online
Even voor de duidelijkheid zoals Anders in zijn presentatie een foreach implementeert:
C++:
1
2
3
4
5
6
7
8
9
public class List
{
    internal object[] elements;
    internal int count;

    public object foreach() {
        for (int i = 0; i < count; i++) yield elements[i];
    }
}


Dus geen return, maar wel een return type. Wat me trouwens nou wel interessant lijkt is of je ipv object bv ook 'int' of een andere baseclass kan meegeven, en dat daar compile-time op gecontroleerd wordt.

Verwijderd

Orphix schreef op 13 november 2002 @ 20:10:
Wat me trouwens nou wel interessant lijkt is of je ipv object bv ook 'int' of een andere baseclass kan meegeven, en dat daar compile-time op gecontroleerd wordt.
Ja toch? Er staat immers in het white papers document van Microsoft:
The return type is determined by the user

[ Voor 0% gewijzigd door Verwijderd op 13-11-2002 20:32 . Reden: link naar white paper toegevoegd ]


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
Verwijderd schreef op 13 november 2002 @ 20:10:
[sub]Die anonymous methods vond ik juist 1 van de mindere dingen in Java... ;) Voor korte methods zou 't handig kunnen zijn, maar waarom definieer je er dan niet gewoon ff een method voor? Zeker voor het terug kunnen vinden van code, lijkt 't me niet zo praktisch. Of zouden die wel ook gewoon in de combo gezet worden? Ik zie daar dus niet echt de voordelen van, maar eerder nadelen...
Zie je het voordeel ook niet voor een ListenerEvent van bijv het sluitkruisje (hoef je niet te hergebruiken) of voor bijv een actie aan een knop die maar 1x in de applicatie voorkomt? Het is dan gewoon een lekkere compacte syntax, die een class defenition scheelt.
(*) als een class te groot wordt, heb je er nml. IMHO niet goed genoeg over naged8
Zolang de taal niet met open objects kan omgaan (en ik me moet behelpen met Visitors ;) ) kan het in sommige gevallen niet voorkomen worden dat de class 'groot' wordt.

Neem bijvoorbeeld een GuiFactory welke voor elke widget een methode moet hebben.

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:54
Verwijderd schreef op 13 november 2002 @ 20:10:
Lees/typ ik nou zo langzaam of zijn jullie nou zo snel? (Toen ik begon met lezen stonden er nog geen reacties en inmiddels al 3!
Jij bent sloom. :+
offtopic:
Gebruiken jullie altijd maar 1 class-file per class?
Ja. Een file -> 1 class. Geen meerdere classes in 1 file. :Y)
(*) als een class te groot wordt, heb je er nml. IMHO niet goed genoeg over naged8

Mwah, niet noodzakelijk....

https://fgheysels.github.io/


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
whoami schreef op 13 november 2002 @ 20:56:
Ja. Een file -> 1 class. Geen meerdere classes in 1 file. :Y)
Jij schrijft inner classes in aparte files? Klasse! :P

  • Orphix
  • Registratie: Februari 2000
  • Niet online
Ik ben het wat grote classes betreft wel eens met Puckly. Microsoft geeft bijvoorbeeld als argument dat het handig is als je class gedeeltelijk gegenereerd wordt en gedeeltelijk eigen code is. Dit lijkt me heel erg vies. Wat is er mis met compositie?
Maar kijk eens naar de .NET framework welke class is daar op zichzelf nou enorm groot (qua declaraties)? Grote classes kunnen noodzakelijk zijn (maar dan betekent dit nog vaak dat de definities lang zijn, niet het aantal methodes) maar duiden vaak gewoon op verkeerd ontwerp.

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:54
Glimi schreef op 13 November 2002 @ 20:59:
[...]

Jij schrijft inner classes in aparte files? Klasse! :P


:X Glimi valt de mieren weer lastig....

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 22:54
Hier is er trouwens een site met dingen die de maker van die site niet zo goed vind in .NET
http://www.veridicus.com/tummy/programming/dotnetshame.asp

(oa dus het gebrek aan anonymous methods.....)

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op 13 november 2002 @ 19:07:
Vandaag las ik op GotDotNet volgend artikel:

New language features

Hier staat dat er in de volgende 'major' release van C# vier belangrijke nieuwe features in C# komen:
- Generics
Ik ben dus helemaal voor generics. En verder kan je er meer mee doen dan alleen wat sneue lijstjes typesafe te maken. Ik kan veel beter generieke complexe objecten maken mbv geparametriseerde polymorphisme.
- Iterators
En die iterators zijn ook wel handig
.
- Anonymous methods
In functionele talen is het niet geheel ongebruikelijk om anonieme functies te gebruiken, maar ik kan er eerlijk gezegd niet warm of koud van worden. Ik denk dat je snel risico loopt dat je onleesbare krengen krijgt (heb ze ook wel eens gebruikt in Nice).
- Partial types
Als dat richting open object gaat, dan ben ik daar helemaal voor :D fuck encapsulation!

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

Alarmnummer

-= Tja =-

Orphix schreef op 13 november 2002 @ 19:47:
De anonymous methods vind ik persoonlijk wel handig. In Java gebruik ik ze vrij vaak en vooral voor simple eventhandling (mouse-click die direct 1 functie aanroept) is het erg handig en bovendien ook leesbaarder.
Dan heb jij een nieuwe feature in java ontdekt: hogere orde functies (een functie die een functie mee kan krijgen als argument). Java ondersteunt dit helaas niet en zal daarom ook zeker geen anonieme functies ondersteunen. Wat jij bedoelt zijn anonieme classes :)

[edit]
De oplossing voor java is het design pattern : Strategy Hiermee kan je een functie wrappen in een class. Stel dat je een lijst hebt, en je wilt op die lijst een filtering aanbrengen. Je zou dan als argument een functie kunnen meegeven die controleerd of een element goed is of niet. Voldoet het element dan mag hij meegenomen worden in het resultaat, en anders dus niet :)

Je zou het dan als volgt kunnen aanpakken:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface Accept<T>{
   boolean accepts(T t);
}

class List<T>{
   ....
   List filter(Accept<T> a){
       List result = new List();
       for(int k=0;k<size();k++){
           if(a.accepts(get(k))
                result.add(get(k));
       }
       return result;
   }
}


Daarnaast is een strategy design pattern nog veel krachtiger dan een hogere orde functie, omdat je dus nu ook informatie van aanroep tot aanroep kan meenemen. vb.

Java:
1
2
3
4
5
6
7
8
9
10
11
class CountingAccept<T> implements Accept<T>{
    int _count = 0;
    Accepts<T> _guest;
    
    CountingAccept(Accept<T> guest){_guest = guest;}

    boolean accepts(T t){
          _count++;
          return _gues.accepts(t);
    }
}


Hiermee kan je bijhouden hoe vaak een aanroep is gedaan. Dit is iets wat je met een functie niet zo snel voor elkaar kan krijgen (je zou dan gebruik moeten maken van 'globale' variablen.

ps: voor de liefhebbers, in het laatste voorbeeldje is het 'proxy design pattern' gebruikt. Damn I love interfaces :P

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

Alarmnummer

-= Tja =-

whoami schreef op 13 november 2002 @ 20:56:
Ja. Een file -> 1 class. Geen meerdere classes in 1 file. :Y)
Ik bundel spul bij elkaar wat bij elkaar hoort en ik vind het absoluut niet erg om innerclasses te gebruiken. Ze zijn meestal dermate klein dat daardoor geen onleesbare code onstaat.

Verwijderd

:o Volgens [u]die Randstad-test[/u] had ik een score van 393, met een nauwkeurigheid van 1... toch nog niet snel genoeg :|
Ja. Een file -> 1 class. Geen meerdere classes in 1 file. :Y)
Alarmnummer schreef op 13 november 2002 @ 22:23:
Ik bundel spul bij elkaar wat bij elkaar hoort en ik vind het absoluut niet erg om inner classes te gebruiken. Ze zijn meestal dermate klein dat daardoor geen onleesbare code onstaat.
Ja, wat (kleine) "helper" classes of wat enums gebruik ik idd ook vaak gewoon binnen een class en/of classfile (volgens mij bedoelde whoami dat ook :)), maar over 't algemeen is 't toch: 1 file per class en ik heb niet de behoefte om daar meer files van te moeten maken, omdat de classes niet zo extreem groot zijn.
Ik kan me ook echt niet voorstellen dat je zo'n grote classfile krijgt, waardoor de behoefte zou ontstaan om er 2 files van te maken. Dan heb je toch een fout ontwerp, denk ik... >:) Maar op iedere regel bestaat natuurlijk een uitzondering. ;)
Bij het splitsen in 2 (of meer) files kun je ze straks idd ook over meerdere assemblies verdelen!
Alarmnummer schreef op 13 November 2002 @ 22:19:
In functionele talen is het niet geheel ongebruikelijk om anonieme functies te gebruiken, maar ik kan er eerlijk gezegd niet warm of koud van worden.
Precies: in functionele talen (zoals Haskell) is het imo eerder iets wat wel handig is dan in een OO-omgeving. Maar ik kan er ook niet echt warm of koud van worden: hoewel ik het het zeker niet zal gebruiken, kan ik me voorstellen dat 't voor luie mensen een uitkomst zal zijn... ;)
Als dat richting open object gaat, dan ben ik daar helemaal voor :D fuck encapsulation!
boehoe :'( dat meen je toch niet echt?

offtopic:
whoami schreef op 13 November 2002 @ 21:44:
Hier is er trouwens een site met dingen die de maker van die site niet zo goed vind in .NET
(oa dus het gebrek aan anonymous methods.....)

offtopic:
Met de meeste van die dingen die daar genoemd staan, ben ik 't idd wel eens. Hij draagt ook vrij constructieve oplossingen aan, dus da's ook erg positief. Ook zijn opmerkingen vwb strategy design pattern snijden veel hout...

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
whoami: [Generics]Idd, en je hoeft niet telkens te gaan casten enzo als je objects uit een ArrayList haalt.
Dat is inderdaad een voordeel wat het meest voor de hand ligt als je vanuit je huidige code naar de toepassing van generics kijkt. Gelukkig zijn generics echter buiten de vanzelfsprekende toepassing in collections veel breder inzetbaar. Dit komt omdat het een geheel nieuwe (nou ja, voor Java en C# dan ;) ) vorm van polymorphisme invoert.
Alarmnummer drukt dat zo uit: En verder kan je er meer mee doen dan alleen wat sneue lijstjes typesafe te maken. Ik kan veel beter generieke complexe objecten maken mbv geparametriseerde polymorphisme.
Deze toepassing komt er concreet op neer dat je door generics en covariante return typen veel algemerere interfaces en methoden kan maken. Je kan interfaces (en uiteraard ook klassen) algemener toepasbaar maken en daardoor kan je meer generieke code schrijven. Het gaat daarbij dus met name om code die gebruik maakt van een geparameterizeerd type en niet zozeer om het geparameterizeerde type zelf.

Het meest extreme geval is de interface voor een Function. Deze kan je nu best wel fraai definieren in Java/C# :

code:
1
2
3
public interface Function<A, R> {
  public R apply(A argument);
}


Dankzij de parameters en in combinatie met covariante return typen kan je met deze eenvoudige interface buitengewoon veel doen. Ze werken in feite als een soort krachtigere versie van functie-pointers: ze kunnen een state hebben. Je kan deze functies bijvoorbeeld in veel gevallen heel goed gebruiken als generieke interface implementatie van een Strategy pattern. Denk bijvoorbeeld ook eens aan de renderers in Java's Swing: als je deze een Function<A, String> meegeeft kan je hier een veel krachtiger systeem van maken dan de huidige aanroep van de toString functie. Het fraaie is hier in bijzonder dat je geen hele specifieke interface meer nodig hebt. Dit zorgt ervoor dat je de implementaties in veel meer gevallen kan gebruiken, precies het voordeel wat ik net beschreef :) .

( Bovendien kan je af en toe ook nog eens net doen of je in een echte taal werkt en dus een functie compositie, map of fold gebruiken ;) ).
marcusk: Ohja, generics zijn imo eigenlijk onmisbaar voor een OO taal
Puckly: Vind ik ook. Ik snap echt niet waarom dat er nog niet in zit.
Onmisbaar kan ik me goed in vinden, dat ze er nog niet in zitten kan ergens wel begrijpen. Ten tijde van het ontstaan van Java leefden generics al behoorlijk, maar er waren maar weinig productie OO talen a la Java/C# die geparameterizeerde typen kenden. C++ wordt daarbij over het algemeen niet meegerekend omdat de template methode absoluut niet te vergelijken is met generics (waarbij ik geen van beide oplossingen wil bekritiseren). In de allereerste Java Language Reference kan je in het voorwoord al een verwijzing lezen naar het 'bezig zijnde' onderzoek naar geparameterizeerde typen. De laatste jaren is op dit gebied erg veel gebeurt. Voor die tijd was het naar de mening van velen te controversieel/onvolwassen/niet uitgekristalliseerd en daarom niet geschikt voor produktie talen als Java en C#. Voor Java was het een gewaagde stap geweest, voor C# al een stuk minder. In het geval van C# vind ik het inderdaad wel vreemd dat hier niet gelijk aan gewerkt is.
Orphix: De anonymous methods vind ik persoonlijk wel handig. In Java gebruik ik ze vrij vaak en vooral voor simple eventhandling (mouse-click die direct 1 functie aanroept) is het erg handig en bovendien ook leesbaarder.
whoami: Mwah, ik zie er niet echt het nut/handigheid van in enzo....
Het handige is dat anonieme methoden (en ook de inner-classes van Java) lexical scope hebben: ze kunnen lokale variabelen gebruiken van de methode waarin ze gedefinieerd zijn. Dat zorgt ervoor dat soms erg handig kunnen zijn: je hoeft al die state nu niet mee te gaan geven. Uiteraard moet je hier wel een beetje bewust mee omgaan.

Overigens heb ik het nog niet officieel bevestigt gezien dat de C# anonieme methoden ook daadwerkelijk lexical scope hebben. Iemand wees me op een sample waaruit je zou kunnen afleiden dat ze lexical scope gaan hebben, maar het is uiteraard nog maar de vraag of dat sample al compileert ;) . Als ze geen lexical scope hebben, zie ik maar heel erg weinig voordeel (wat mij betreft zit daar dus het voornaamste voordeel).

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


Verwijderd

Over dit onderwerp is er trouwens op dit moment een chat:
http://communities2.micro...room.aspx?siteid=34000014

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Overigens kunnen local classes (zo heten ze eigenlijk: inner classes zijn klassen in klassen, lokale klassen zijn klassen in methoden) in Java alleen gebruik maken van de lokale variabelen die final zijn gedeclareerd. Hiervoor is namelijk een logisch compilatie schema te bedenken. Gebruik van niet-final variabelen en assignments zijn dus niet toegestaan.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


Verwijderd

mbravenboer schreef op 13 november 2002 @ 23:12:
marcusk: Ohja, generics zijn imo eigenlijk onmisbaar voor een OO taal
Puckly: Vind ik ook. Ik snap echt niet waarom dat er nog niet in zit.
mbravenboer:Onmisbaar kan ik me goed in vinden, dat ze er nog niet in zitten kan ergens wel begrijpen. [...] In het geval van C# vind ik het inderdaad wel vreemd dat hier niet gelijk aan gewerkt is.
Precies! Ze wilden zich juist positief onderscheiden van Java en dat is op veel punten ook heel goed gelukt (en ja, op andere punten wat minder), maar die generics hadden ze er toch al wel meteen in kunnen stoppen? Het is toch erg OO en bovendien kun bijv. je de penalty voorkomen die je anders soms kunt krijgen op het boxen en unboxen...
Het handige is dat anonieme methoden (en ook de inner-classes van Java) lexical scope hebben: ze kunnen lokale variabelen gebruiken van de methode waarin ze gedefinieerd zijn. Dat zorgt ervoor dat soms erg handig kunnen zijn: je hoeft al die state nu niet mee te gaan geven. Uiteraard moet je hier wel een beetje bewust mee omgaan.
Ja, maar ik vind lexical scope juist helemaal niet handig (of handig wel... netjes is een beter woord ;))! Geef alle parameters die je in je method nodig hebt, maar lekker door. :)
Ik vind het voorbeeld zoals dat in de eerder genoemde white papers document van Microsoft als voorbeeld gegeven staat echt :r code:
code:
1
2
3
4
5
6
7
listBox = new ListBox(...);
textBox = new TextBox(...);
button = new Button(...);
button.Click += new EventHandler(sender, e)
{
    listBox.Items.Add(textBox.Text);
};

Je gaat toch ook geen global variables gemisbruiken, omdat je die in meerdere methods nodig hebt? Dan geef je ze door, zodat duidelijk is wat de interface is. :)
Overigens heb ik het nog niet officieel bevestigt gezien dat de C# anonieme methoden ook daadwerkelijk lexical scope hebben. Iemand wees me op een sample waaruit je zou kunnen afleiden dat ze lexical scope gaan hebben, maar het is uiteraard nog maar de vraag of dat sample al compileert ;)
Bovenstaand sample? ;) Sowieso zal het natuurlijk nog niet compileren, zolang het nog niet in 't framework zit. :) Eerst nog maar ff kijken of die Everett-versie die in februari 2003 uitkomt iets is...

Ik bedenk me nu trouwens dat bovenstaand sample nog niet eens echt een goed voorbeeld is van lexical scope, omdat je die list- en textBox ook natuurlijk gewoon had kunnen benaderen als je de .Click-method niet als anonymous method had gedeclareerd.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Puckly: Geef alle parameters die je in je method nodig hebt, maar lekker door. :)
Het punt is eigenlijk juist dat dat niet kan ;) . Als je een functie pointer meegeeft aan een andere methode, verzorgt deze de parameters van de aanroep. Je kan hier zelf weinig invloed op uitoefenen. Het enige wat je kan doen is de parameters ook nog meegeven aan de methode die de functie aan moet gaan roepen. Vaak is dit echter niet mogelijk omdat het om een specifieke toepassing van de methode gaat.

Het probleem is in feite dat je dus helemaal geen state aan de anonieme methode kan meegeven, behalve dan uiteraard voor de variabelen in de klassen. Juist omdat dit gezien de implementatie van delegates best mogelijk is, zijn anonieme methode met lexical scope wel een logische stap denk ik. Je kan namelijk de lokale variabelen op geen enkele andere fraaie manier meegeven (voor zover ik weet ... ).

In Java pas je in feite hetzelfde patroon toe als je de implementatie van in interface die je meegeeft aan een methode (bijvoorbeeld een Comparator aan een sort methode) state geeft via variabelen in de implementatie van de interface. Je bent dan eigenlijk handmatig in grote lijnen hetzelfde aan het doen als via anonieme functies met lexical scope. Voordeel is misschien dat het duidelijker is, nadeel is dat het meer werk is.
Bovenstaand sample? ;)
Nee, het was op de Mono mailing list toen de whitepaper er nog niet was. Volgens mij ging het om 1 van de samples bij de presentatie. Ik zal even zoeken.
Sowieso zal het natuurlijk nog niet compileren, zolang het nog niet in 't framework zit. :) Eerst nog maar ff kijken of die Everett-versie die in februari 2003 uitkomt iets is...
Rotor kent al een generics patch en ik zou niet gek opkijken als ze zelf intern al het een en ander hebben getest met de andere voorstellen: je gaat niet zo'n uitbreiding presenteren zonder wat language prototyping. Bovendien zijn sommige nieuwe zaken slechts compiler kwesties en geen uitbreidingen van de IL ...
Ik bedenk me nu trouwens dat bovenstaand sample nog niet eens echt een goed voorbeeld is van lexical scope, omdat je die list- en textBox ook natuurlijk gewoon had kunnen benaderen als je de .Click-method niet als anonymous method had gedeclareerd.
Hum ik had nog ff moeten lezen toen ik ging replyen ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Het gaat om deze sample uit de presentatie:

code:
1
2
3
4
5
6
   ArrayList GetLargeAccounts(double minBalance) {
      return accounts.Select(
         new Filter(a) {
            return ((Account)a).Balance >= minBalance;
         });
   }


minBalance wordt hier gebruikt in deze anonieme methode. Dit is een lokale variabele (parameter, maar dat maakt niet zoveel uit). Dit duidt denk ik wel op de mogelijkheid van lexical scope. Je ziet het voordeel hiervan ook heel duidelijk gepresenteerd op deze slide (account, twee slide van anonieme methoden). Dit is precies wat ik hierboven beschreef.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Overigens zie je daar nog een ranzige cast, die wordt met generics natuurlijk overbodig :+ . Het signatuur van de Filter delegate kan dan veel krachtiger.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


Verwijderd

mbravenboer schreef op 14 November 2002 @ 00:45:
Het punt is eigenlijk juist dat dat niet kan ;) . Als je een functie pointer meegeeft aan een andere methode, verzorgt deze de parameters van de aanroep. Je kan hier zelf weinig invloed op uitoefenen. Het enige wat je kan doen is de parameters ook nog meegeven aan de methode die de functie aan moet gaan roepen. Vaak is dit echter niet mogelijk omdat het om een specifieke toepassing van de methode gaat.
[...]
Wat je hier beschrijft, is imo erg procedureel gericht (functionele decompositie ensow) en (dus ;)) niet thuishoren in een OO-language als C#.

Bedoel je dit: :?
Als je (bijvoorbeeld) een bepaalde delegate hebt voor een bepaald event, ben je gedwongen om als parameters object sender en EventArgs e mee te geven en kun je als je extra parameters in je eigen method (eventhandler) nodig hebt, die niet toevoegen.

Als je zoiets bedoelt, dan zou mijn antwoord daarop zijn: dan maak je een eigen MyEventArgsClass die je afleidt van EventArgs; definieer je daar een constructor met de parameters die je nodig hebt en zet je die parameters als property van je MyEventArgsClass.

Als je iets anders bedoelt, zou je dan misschien een concreet voorbeeld (*) kunnen geven, waarbij er echt een duidelijk voordeel is voor het gebruiken van anonymous methods? :) (Of een nadeel, omdat je geen anonymous method kunt gebruiken.)
mbravenboer schreef op 14 November 2002 @ 00:45:
Voordeel is misschien dat het duidelijker is, nadeel is dat het meer werk is.
Ik zou persoonlijk toch gaan voor de duidelijkheid... (8>
(en voor OO ;))

Ik ben 't overigens wel met je eens dat als je anonymous methods gebruikt, lexical scope dan wel erg praktisch zou kunnen zijn.

(*) misschien in een andere thread, omdat we anders teveel off-topic raken?

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Wat je hier beschrijft, is imo erg procedureel gericht (functionele decompositie ensow) en (dus ) niet thuishoren in een OO-language als C#.
Mwah, dat valt wel mee denk ik ;) . Jij gaf aan dat je in plaats globale variabelen liever werkt met parameters indien mogelijk. Hier valt zeker wat voor te zeggen: over variabelen in een klasse moet je nadenken. Ze ontstaan als het goed is niet uit noodzaak.
Als je (bijvoorbeeld) een bepaalde delegate hebt voor een bepaald event, ben je gedwongen om als parameters object sender en EventArgs e mee te geven en kun je als je extra parameters in je eigen method (eventhandler) nodig hebt, die niet toevoegen.
Dat is inderdaad wat ik bedoel.
Als je zoiets bedoelt, dan zou mijn antwoord daarop zijn: dan maak je een eigen MyEventArgsClass die je afleidt van EventArgs; definieer je daar een constructor met de parameters die je nodig hebt en zet je die parameters als property van je MyEventArgsClass.
Maar dit is niet de oplossing: je hebt zelf namelijk helemaal geen invloed op de inhoud van de EventArgs. De parameters die worden meegegeven worden bij de aanroep van een delegate instantie worden gekozen door het stuk code waaraan je de delegate instantie mee hebt gegeven. Je roept de delegate dus niet zelf aan. De aanroepende code moet dus kennis hebben van de parameters die nodig zijn voor de aanroep van de delegate.

Als je echter 'extra parameters' nodig hebt, is dat een specifieke situatie: slechts 1 mogelijke toepassing van de delegate en de code die de delegate gebruikt. Je kan hierin op dit moment alleen maar via klasse variabelen 'extra parameters' meegeven aan de delegate. Je zou deze extra parameters best kunnen toevoegen aan de delegate en de code die de delegate aanroept, maar dan moet die code dus wel kennis hebben van deze specifieke situatie en worden andere situaties uitgesloten.

Via de anonieme methode met lexical scope ontstaat er een nieuwe manier om extra variabelen te gebruiken de methode die zal worden aangeroepen. Je hoeft dit nu niet meer percee via klasse variabelen te doen: de anonieme methode kan ook gebruik maken van de lokale variabelen van de methode waarin de anonieme methode zich bevindt.

Daarom lost het dus echt iets op en dus voegt het niet alleen gemak toe, maar maakt wellicht zelfs af en toe op kleine schaal een beter design mogelijk.
Als je iets anders bedoelt, zou je dan misschien een concreet voorbeeld (*) kunnen geven, waarbij er echt een duidelijk voordeel is voor het gebruiken van anonymous methods? (Of een nadeel, omdat je geen anonymous method kunt gebruiken.)
Je kan de situatie heel goed vergelijken door de delegates vol uit te programmeren in Java: je ziet dan precies op welke manieren je parameter mee kan geven aan de functie en waarom de lexical scope dus iets toevoegt. Je moet dan namelijk zelf de declaratie van de gebruikte variabelen regelen en dan zie je precies wat er gebeurt.

Het lijkt allemaal wat simpel, maar als je het goed bekijkt wordt de situatie precies duidelijk.

Stel dat je deze onzinnige interface hebt:
Java:
1
2
3
public interface Add {
  public int apply(int value);
}

Je ziet natuurlijk wel de gelijkenis met een gewone methode: het is in feite gewoon een methode die we bekijken als een klasse. De interface is daarom 1 op 1 te vergelijken met een delegate declaratie in C# :

C#:
1
public delegate int Add(int value);


Een implementatie van de Java interface Add zou een bepaald getal (niet gedefinieerd welke) op moeten tellen bij de value en het resultaat opleveren. Een mogelijke implementatie is dus deze:

Java:
1
2
3
4
5
public class Increment implements Add {
  public int apply(int value) {
    return value + 1;
  }
}


Een implementatie van de C# delegate Add is bijvoorbeeld deze methode:

C#:
1
2
3
public int Increment(int value) {
  return value + 1;
}


Van de Add delegate kan je zo een instantie aanmaken met de methode Increment:

C#:
1
Add increment = new Add(Increment);


Van de Java klasse Increment kan je zo een instantie maken, die je uiteraard kan behandelen als 'een Add' :

Java:
1
Add increment = new Increment();


Stel nu echter dat we een generieke implementatie van de Add willen maken, die een getal x optelt bij de geven value. De Java klasse Increment kunnen we hier voor gebruiken als basis.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
public class GenericAdd implements Add {
  private int _x;

  public GenericAdd(int x) {
    super();
    _x = x;
  }

  public int apply(int value) {
    return value + x;
  }
}

We hebben dus in de klasse GenericAdd een veld toegevoegd: x. Er was al een klasse (die eerste Increment heette), we hebben nu alleen maar een constructor gemaakt en een veld toegoevoegd. Een instantie aanmaken is simpel: new GenericAdd(5) bijvoorbeeld.

In C# wordt het lastig om de methode Increment aan te passen: we moeten de x meegeven aan de methode, maar hoe?

C#:
1
2
3
public int GenericAdd(int value) {
  return value + x;
}

Dit kan dus alleen via een nieuw veld in de klasse, die tot nu toe irrelevant was: voor hetzelfde geldt was het zelfs een statische methode. Hierdoor wordt er de oude manier van werken dus eigenlijk onmogelijk en moeten we alleen maar omdat we toevallig die x nodig hebben (een klein beetje) anders gaan werken.

Met de komste van anonieme methoden wordt dit anders: we kunnen de GenericAdd nu definieren als anonieme methode in de construrende methode en deze gebruik laten maken van een lokale variabele. Bijvoorbeeld:

C#:
1
2
3
4
public void DoSomething() {
  int x = 5;
  Add addx = new Add(value) { return value + x; };
}

Let op de code die uiteindelijk met de Add delegate gaat werken, dus niets weet van de x en deze dus niet meegeeft als parameter. Ook hebben we geen klasse variabelen in de onbekende omringende klasse toegevoegd.

Maar in die Java implementatie voel je wel een veld toe? Ja inderdaad, maar het punt is juist dat er daar al een klasse was die nodig was omdat Java geen delegates kent. De aanroepende methode weet ik ook niets van de velden in de implementatie en de velden kunnen geinitialiseerd worden met de lokale variabelen van de methode die de GenericAdd instantie aanmaakt. Het heeft dus wat weg van lexical scope en daarom zou je het ook als anonieme lokale klasse kunnen implementeren:

Java:
1
2
3
4
5
6
7
8
public void doSomething() {
  final int x = 5;

  Add addx = new Add() {
    public int apply(int value) {
      return value + x;
    };
}

Merk op hoe ontzettend veel dit lijkt op de anonieme methode in C# ....

Ik geef direct toe dat het voorbeeld een beetje vaag is: wat heb je nu aan een GenericAdd als deze alleen te gebruiken is in 1 methode? ;) . Het gaat echter om het idee en dat wordt hier denk ik goed duidelijk.
Ik zou persoonlijk toch gaan voor de duidelijkheid... (en voor OO )
Ik wil hier ook allerminst een pleidooi houden voor delegates, maar als je toch al delegates hebt is de anonieme methode met lexical scope een goede toevoeging :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • whoami
  • Registratie: December 2000
  • Laatst online: 22:54
Ik heb eens zitten nadenken over die iterators... :+

Wanneer zou je gebruik maken van zo'n iterator en wanneer zou je zelf een iterator class schrijven mbvh 'iterator design pattern'?
Als je op verschillende manier door je data moet kunnen scrollen, dan is het natuurlijk het best om zelf iterator classes te schrijven, maar is het eigenlijk wel de moeite om dat te doen als je maar enkel forward-only bv door je data wilt scrollen?

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op 15 November 2002 @ 19:10:
Ik heb eens zitten nadenken over die iterators... :+

Wanneer zou je gebruik maken van zo'n iterator en wanneer zou je zelf een iterator class schrijven mbvh 'iterator design pattern'?
Ik denk niet dat je die vraag moet stellen. De iterator design pattern is gemaakt om een ontkoppeling aan te bieden op de structuur van de collectie waar de elementen in zitten. Zij geven je deze iterator al, dus je hoeft er zelf niet nog een te maken :)
Als je op verschillende manier door je data moet kunnen scrollen, dan is het natuurlijk het best om zelf iterator classes te schrijven, maar is het eigenlijk wel de moeite om dat te doen als je maar enkel forward-only bv door je data wilt scrollen?
Ik neem aan dat je met forward-only bedoelt dat je van voren naar achteren gaat. Zo gauw je dit gaat zeggen, doe jij al weer een aanname over de structuur van die collectie, want je weet namelijk dat het een listachtige structuur is. Dit kan problemen opleveren omdat jij dus een bepaalde voorwaarde aan een object gaat stellen en dat object dus niet meer vrij is om de collectie structuur aan te passen.

Maar ik moet ook eerlijk zijn. Ik vind de iterator ook niet overal toepasbaar. Regelmatig heb ik een structuur zoals een Hashstructuur of een Liststructuur en dan heb ik daar geen problemen mee om deze structuur naar buiten kenbaar te maken.

Ik ga meestal zelfs nog een stapje verder. Ik durf zelfs die collecties naar buiten toe af te geven. Maar dan doe ik ze wel even lief in een unmodifiable wrapper zodat niemand mijn structuren meer kan vereuken :)

En om het helemaal een beetje eng te maken. Ik ben bezig met een mvc librarie met een hele krachtige controller en model. Aan de model zit een controller, met alle listenener en vetolisteners. Iedereen mag met die model aan de slag, maar de vetolisteners verhinderen dat de lijsten verneukt worden. Dit project staat al een tijdje op een laag pitje omdat er nog een enorme beperking in Nice zit mbt geparametriseerde polymorfisme.
Pagina: 1