Cookies op Tweakers

Tweakers maakt gebruik van cookies, onder andere om de website te analyseren, het gebruiksgemak te vergroten en advertenties te tonen. Door gebruik te maken van deze website, of door op 'Ga verder' te klikken, geef je toestemming voor het gebruik van cookies. Wil je meer informatie over cookies en hoe ze worden gebruikt, bekijk dan ons cookiebeleid.

Meer informatie
Toon posts:

[C#][discussie] Lekker veel var gebruiken?

Pagina: 1 2 Laatste
Acties:

Onderwerpen


  • pedorus
  • Registratie: januari 2008
  • Niet online
Niet zozeer een probleem, maar meer een discussie. :p Ik plaatste vandaag een mooi stukje hobbycode met nogal veel gebruik van var erin (en iets te korte variabelenamen), en er kwamen gelijk wat reacties op het gebruik van type interference (var) in plaats van expliciete types (int, string, StringBuilder, enz.):
BM schreef op dinsdag 09 februari 2010 @ 12:44:
offtopic:
Mag ik trouwens zeggen dat je irritant gebruik maakt van 'var'? :X
MBV schreef op dinsdag 09 februari 2010 @ 14:47:
offtopic:
viel mij ook al op ja. Heeft in deze context toch geen enkel nut, en kan toch ook voor een lagere performance zorgen? Los daarvan haal je alle voordelen van een strongly typed language weg, ga dan lekker ironPython gebruiken als je in .NET wilt spelen :X
Dat laatste is overigens niet waar, de volgende declaraties leveren exact dezelfde IL/machinecode op:
C#:
1
2
3
4
5
var integer = 100;
int integer = 100;

List<string> stringList = new List<string>();
var stringList = new List<string>();

Ook in het verleden hebben meer mensen hier zich over het gebruik van var verbaasd:
whoami schreef op vrijdag 11 januari 2008 @ 09:06:
Het is idd mogelijk om dat te doen, maar, het is -imho- bad practice om dat te doen als je het type kent.
Waarom zou je , in jouw voorbeeld die Blaat als var declareren als je het type kent ?
Als var enkel zou bedoeld zijn als 'shorthand', dan zie ik er het nut niet van in, en dan hadden ze eigenlijk var gewoon uit de specs kunnen halen.
RobIII schreef op donderdag 02 oktober 2008 @ 17:00:
Even iets compleet anders: waarom is alles "var" bij jou?
Haan schreef op donderdag 27 augustus 2009 @ 13:26:
Nu het toch over Resharper gaat, er zit ook een optie in om C# code te 'upgraden' naar .Net 3.0, onderdeel daarvan is het gebruik van 'var' voor lokale variabelen, kan iemand misschien uitleggen wat het voordeel van is?
In mijn opinie is het gewoon minder tikwerk en (belangrijker) beter leesbaar om vaak var te gebruiken. Minder typwerk lijkt me duidelijk. Zelfs VS.NET is er standaard op ingesteld: typ "fore[tab][tab][tab]" in vs.net en je foreach-loopje met var staat klaar. Leesbaarheid is een kwestie van opinie, maar typenamen kosten nu eenmaal ruimte, die beter aan andere dingen kan worden besteed. En als je het type perse wil weten, zie je het type vanzelf als je de muis er even boven houdt in je IDE. In Google's nieuwe taal Go wordt ook een soort van var gebruikt, met als redenatie:
Reduce typing. Let the language work things out.
No stuttering; don't want to see
foo.Foo *myFoo = new foo.Foo(foo.FOO_INIT)
Avoid bookkeeping.
But keep things safe.
Waar ik me graag bij aansluit. :p De compiler/IDE lost het type-probleem wel op, en voor de leesbaarheid zijn ze vaak onnodig als je eenmaal aan var bent gewend. Wellicht met alle bool's en int in een for-loop als uitzondering. Dus niet:
C#:
1
2
3
    var selectedIsChild = NodeIsChildOf(TreeSelectedFeedsNode, selectedNode);
    var isSmartOrAggregated = (selectedNode.Type == FeedNodeType.Finder ||
                                          selectedNode.Type == FeedNodeType.SmartFolder);
Natuurlijk is dit ook op de rest van het internet een discussie:
De compiler kan dat best zelf uitzoeken! (De toekomst van C# deel 2)
Aantal voor- en tegenstanders
Resharper (v4) plijt voor var
Jeff Atwood (Coding Horror) plijt voor var
Can the C# ‘var’ Keyword be Misused?
MVP voor var
C# - Do you use “var”?
Het stukje "Overuse of var can make source code less readable for others." is overigens geschrapt uit de .NET-documentatie.

Mijn idee is dus dat het niet-gebruiken van var meestal iets uit het verleden is, en dat het wordt gedaan vanuit consistentie-oogpunt. In serieuzere code gebruik ik het nog weinig, maar in hobby-code zoals hier gebruik ik (zoveel mogelijk) var. In de toekomst voorzie ik dat var steeds meer gebruikt gaat worden. Misschien dat het ook wel aan java wordt toegevoegd. :p Zijn er hier al mensen die var in professionele code zo vaak mogelijk gebruiken? Zijn er mensen die wel problemen met het (toenemend) gebruik van var voorzien?

Vitamine D tekorten in Nederland | Corona: wat niet gepost kan worden


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

Als je het niet erg vindt behandel ik dit even als een algemeen static type inference topic, en gaat het dus ook op voor vergelijkbare features in andere talen zoals "auto" in C++0x :)

Het is voornamelijk bedoeld om nutteloze verbositeit te voorkomen. Iets als "var stringList = new List<string>()" ben ik helemaal voor, compleet overbodig om voor stringList nog een keer het type te specificeren terwijl dat wel duidelijk is uit de new. Ook is het handig bij functies die een wat complexere generic/template types retourneren. Iet als "std::map<int, std::vector<float>>::iterator it = myMap.find(42);" tikt ook wat onhandig. Nou zijn daar nog typedefs voor in C++ (kent C# geloof ik niet?), maar die lossen het probleem slechts deels op. Hier maak je feitelijk de afweging tussen verbeterde productiviteit en het verlies van informatie in het stuk code.

Dat betekent dat je het ook kunt overdrijven, zoals je laat zien in dat voorbeeld, maar ook een beetje in het stukje code wat je eerder vandaag geplaatst hebt waar imho, even afgezien van het misverstand van de betekenis van 'var', terechte kritiek op kwam :). Bij dingen als "foreach (var c in str)" had ik toch liever "char" gelezen. Met het gebruik van "var" win je geen drol, maar je verliest wel een klein beetje aan informatie.

[Voor 13% gewijzigd door .oisyn op 09-02-2010 23:10]

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • Rickets
  • Registratie: augustus 2001
  • Niet online

Rickets

Finger and a shift

pedorus schreef op dinsdag 09 februari 2010 @ 22:33:
Mijn idee is dus dat het niet-gebruiken van var meestal iets uit het verleden is, en dat het wordt gedaan vanuit consistentie-oogpunt. In serieuzere code gebruik ik het nog weinig, maar in hobby-code zoals hier gebruik ik (zoveel mogelijk) var. In de toekomst voorzie ik dat var steeds meer gebruikt gaat worden. Misschien dat het ook wel aan java wordt toegevoegd. :p Zijn er hier al mensen die var in professionele code zo vaak mogelijk gebruiken? Zijn er mensen die wel problemen met het (toenemend) gebruik van var voorzien?
Ik gebruik het vaak, vooral bij types met lange namen (collections met generics e.d.). Ik heb geen zin om twee keer het type in te moeten tikken of te lezen. Vroeger werkte ik veel met VB.Net en dan was het altijd fijn dat je maar eenmaal het type hoefde aan te geven:

Visual Basic .NET:
1
2
3
4
'Fijn:
Dim grutjes As New Dictionary(Of Integer, Melp)
'Niet fijn:
Dim grutjes As Dictionary(Of Integer, Melp) = New Dictionary(Of Integer, Melp)
C#:
1
2
3
4
// Fijn:
var grutjes = new Dictionary<int, Melp>();
// Niet fijn:
Dictionary<int, Melp> grutjes = new Dictionary<int, Melp>();

In zo’n geval vind ik var fijn werken.
Ik gebruik het ook vaak om gegevens uit een repository in op te slaan. Ik zie snel genoeg aan de naam van de variabele of het een single entity of een collection is wat de repository teruggeeft – het type boeit me dan meestal niet.
Ik gebruik geen var als het type wel relevant is om de omliggende code sneller te lezen en begrijpen, en ook bij value types gebruik ik het niet.

If some cunt can fuck something up, that cunt will pick the worst possible time to fucking fuck it up, because that cunt’s a cunt.


  • user109731
  • Registratie: maart 2004
  • Niet online
Met de heren hierboven. Voor collections is het gewoon erg handig omdat het veel korter is. Maar voor eenvoudige types vind ik het overkill. Ja dat zeg ik als Python-fan, maar C#/C++ zijn andere talen, daar zou ik op z'n minst de 'primitive types' als int, bool, etc. uitschrijven. Het maakt qua typewerk niet uit en voor de lezer is het duidelijker.

Uit een van je voorbeelden:
C#:
1
var selectedIsChild = NodeIsChildOf(TreeSelectedFeedsNode, selectedNode);

Hier is 'bool' slechts een letter meer en leesbaarder (en dan kun je het hier nog aan de naamgeving zien, bij andere typen kan dat vaak niet).

[Voor 21% gewijzigd door user109731 op 09-02-2010 23:24]


  • CoolGamer
  • Registratie: mei 2005
  • Laatst online: 21:55

CoolGamer

What is it? Dragons?

Als het new-statement op dezelfde regel staat is het wel duidelijk met wat voor type je te maken hebt, maar zoals in het voorbeeld van JanDM kan het erg verwarrend zijn.

Ik denk dat een mooie regel kan zijn van wel/niet gebruiken is wanneer het gelijk duidelijk is met wat voor type je te maken hebt en het type een class is.

Ik merk het zelf ook wel wanneer ik werk met C++ in combinatie met iterators voor template classen dat de types erg lang worden en ik denk dat dit er een mooie oplossing voor is.

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


  • pedorus
  • Registratie: januari 2008
  • Niet online
.oisyn schreef op dinsdag 09 februari 2010 @ 23:04:
Nou zijn daar nog typedefs voor in C++ (kent C# geloof ik niet?), maar die lossen het probleem slechts deels op.
Het kan wel, al gebeurd het weinig:
C#:
1
2
3
4
5
using MelpMap = Dictionary<int, Melp>; //in namespace
// Fijn:
var grutjes = new Dictionary<int, Melp>();
// Niet fijn:
MelpMap grutjes = new MelpMap();

Evengoed zie ik liever de eerste, want dan hoef ik nooit met de muis uit te vinden wat het is.
Dat betekent dat je het ook kunt overdrijven, zoals je laat zien in dat voorbeeld, maar ook een beetje in het stukje code wat je eerder vandaag geplaatst hebt waar imho, even afgezien van het misverstand van de betekenis van 'var', terechte kritiek op kwam :). Bij dingen als "foreach (var c in str)" had ik toch liever "char" gelezen. Met het gebruik van "var" win je geen drol, maar je verliest wel een klein beetje aan informatie.
Dat is inderdaad het slechtste voorbeeld; foreach (char ...) was daar op zich beter geweest, al is het maar omdat een foreach op een string ongebruikelijk is, en char typisch iets is dat je uitschrijft.
JanDM schreef op dinsdag 09 februari 2010 @ 23:16:
[...] maar C#/C++ zijn andere talen, daar zou ik op z'n minst de 'primitive types' als int, bool, etc. uitschrijven. Het maakt qua typewerk niet uit en voor de lezer is het duidelijker.
Het punt van een bool altijd uitschrijven is dat een bool gebruikt gaat worden in logica, en nooit zomaar van type kan veranderen. Bij iets als double/decimal kan dat wel. Zeker in testcode zou ik zelf dus liever eerder de eerste doen:
C#:
1
2
var nr = 0.32m;
decimal nr = 0.32m;

Mocht je later besluiten dat een double handiger is, dan gooi je het makkelijker om. Aan de andere kant wil je het in wat serieuzere code eigenlijk juist wel even met de hand nagaan, en scheelt het weinig. Misschien is het inderdaad wel een goed idee om var alleen bij classes/structs te gebruiken. Hoewel, ze lijnen zo wel mooi uit:
C#:
31
32
33
            var str = "appels en peren";
            var iter = 1000000;
            var s = Stopwatch.StartNew();

Maar dit is niet echt productiecode natuurlijk. ;) Voor testcode is het prima.

Vitamine D tekorten in Nederland | Corona: wat niet gepost kan worden


  • whoami
  • Registratie: december 2000
  • Laatst online: 20:44
pedorus schreef op dinsdag 09 februari 2010 @ 22:33:
Niet zozeer een probleem, maar meer een discussie. :p Ik plaatste vandaag een mooi stukje hobbycode met nogal veel gebruik van var erin (en iets te korte variabelenamen), en er kwamen gelijk wat reacties op het gebruik van type interference (var) in plaats van expliciete types (int, string, StringBuilder, enz.):


Ook in het verleden hebben meer mensen hier zich over het gebruik van var verbaasd:

[...]
Ondertussen ben ik er zelf nog niet goed aan uit.
Soms gebruik ik het, soms ook niet.

Als ik 'var' gebruik, is het meestal maar in korte scopes. Zowiezo kan het toch wel eens de leesbaarheid verbeteren, zeker in situaties als:
code:
1
var someDinges = new MyTypeWithAVeryLongTypeName();

Echter, in situaties zoals hieronder, ga ik var dan weer niet gebruiken:
code:
1
var x = someObject.DoSomeMethod();

  • boe2
  • Registratie: november 2002
  • Niet online

boe2

'-')/

De voornaamste reden die ik zie om expliciet te typeren is dat je compiler er veel eenvoudiger fouten en verkeerde typecastings kan uitvissen. Bovendien werkt je intellisense dan volledig correct, wat toch een stuk vlotter werkt :)

'Multiple exclamation marks,' he went on, shaking his head, 'are a sure sign of a diseased mind.' - Pratchett.


  • RobIII
  • Registratie: december 2001
  • Laatst online: 00:20

RobIII

Admin Devschuur®

^ Romeinse 3 ja!

Boeboe schreef op woensdag 10 februari 2010 @ 00:58:
De voornaamste reden die ik zie om expliciet te typeren is dat je compiler er veel eenvoudiger fouten en verkeerde typecastings kan uitvissen. Bovendien werkt je intellisense dan volledig correct, wat toch een stuk vlotter werkt :)
Huh? Var != Object he?
Beginning in Visual C# 3.0, variables that are declared at method scope can have an implicit type var. An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type.




Ik ben 't eens met whoami; ik ben er ook nog niet helemaal uit, maar 't neigt soms naar rommelige code IMHO. En dan doel ik niet zo zeer op de code an sich, maar inderdaad wat eerder aangehaald werd: even testen/prototypen met wat var's, even beetje spelen stoeien en dan voor je 't weet blijven een aantal van die var's die je feitelijk niet had willen gebruiken rondslingeren en eindigen in productiecode zonder dat je er erg in hebt. (Daar zou je natuurlijk ook nog wat warnings uit kunnen laten genereren door code analysis). Then again: heel erg kwaad kan 't natuurlijk ook niet als er 's een keer ergens een unintended var staat. Het type staat net zo vast.

[Voor 44% gewijzigd door RobIII op 10-02-2010 01:43]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Roses are red Violets are blue, Unexpected ‘{‘ on line 32.

Over mij


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

RobIII schreef op woensdag 10 februari 2010 @ 01:06:
(Daar zou je natuurlijk ook nog wat warnings uit kunnen laten genereren door de compiler).
Lijkt me lastig, dan moet een compiler gaan defieren wanneer je het wel en wanneer je het niet mag gebruiken. Waar ligt dan de grens, als het bedoelde type langer is dan N tekens oid? Het lijkt me sowieso niet wenselijk om dan maar altijd die warnings te krijgen.

[Voor 9% gewijzigd door .oisyn op 10-02-2010 01:16]

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • RobIII
  • Registratie: december 2001
  • Laatst online: 00:20

RobIII

Admin Devschuur®

^ Romeinse 3 ja!

.oisyn schreef op woensdag 10 februari 2010 @ 01:16:
[...]

Lijkt me lastig, dan moet een compiler gaan defieren wanneer je het wel en wanneer je het niet mag gebruiken. Waar ligt dan de grens, als het bedoelde type langer is dan N tekens oid? Het lijkt me sowieso niet wenselijk om dan maar altijd die warnings te krijgen.
Ik doelde meer op de (oude) StyleCop/FxCop warnings die sinds VS2005/8(?) onder code analysis vallen. En dan is 't een kwestie van een policy aanmaken naar smaak. Dan zou je kunnen aangeven dat je voor productiecode gewoon een warning op elke var gooit en met een attribuut kun je die warning de kop in drukken waar de var expliciet wél gewenst is. Ik gebruik het zelf niet veel dus ik hanteer waarschijnlijk een beetje geverknulde termen :P

[Voor 36% gewijzigd door RobIII op 10-02-2010 01:44]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Roses are red Violets are blue, Unexpected ‘{‘ on line 32.

Over mij


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

.oisyn schreef op dinsdag 09 februari 2010 @ 23:04:
Bij dingen als "foreach (var c in str)" had ik toch liever "char" gelezen. Met het gebruik van "var" win je geen drol, maar je verliest wel een klein beetje aan informatie.
Geeft de naam "str" niet al genoeg informatie?

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • RobIII
  • Registratie: december 2001
  • Laatst online: 00:20

RobIII

Admin Devschuur®

^ Romeinse 3 ja!

RayNbow schreef op woensdag 10 februari 2010 @ 01:33:
[...]

Geeft de naam "str" niet al genoeg informatie?
str-wat? :P
Jawel, tuurlijk geeft 't genoeg informatie als je er even een kopje koffie bij pakt en op je elfendertigste gaat zitten doorfietsen. Punt is dat var hier wat onhandig gedemonstreerd werd en het juist de leesbaarheid had bevorderd door char uit te schrijven. Dan had je het sneller (en zekerder) begrepen. For all you know is het een List<Stream> die iemand wat onhandig heeft genamed i.p.v. een string. Voor een 3-regel code voorbeeldje is 't nogal snel afgeleid natuurlijk. Voor wat complexere zaken kan dat natuurlijk heel anders liggen; mede afhankelijk van de duidelijkheid in naamgeving natuurlijk.

[Voor 8% gewijzigd door RobIII op 10-02-2010 01:44]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Roses are red Violets are blue, Unexpected ‘{‘ on line 32.

Over mij


  • Soultaker
  • Registratie: september 2000
  • Laatst online: 25-07 13:55
Ik ben zeker voorstander van het weglaten van typeinformatie waar dat niets nuttigs toevoegt. Statische typering is heel fijn, maar teveel expliciete typeinformatie gaat ten koste van het overzicht en de leesbaarheid van de code.

De C++ iterators zijn daar bij uitstek een voorbeeld van, want alle standaardfuncties die iets met iterators doen zijn juist templatefuncties die het niet kan schelen wat het iteratortype nu precies is, als het zich maar als een iterator gedráágt. Het is raar dat je dan als programmeur nota bene wél het exacte type van de iterator met alle benodigde template-parameters uit moet gaan zitten typen (als je geen typedef gebruikt). Misschien dat daardoor ook vele C++ programmeurs zich niet beseffen dat je b.v. een array kunt passen waar een (zeg) output iterator verwacht wordt, omdat ze denken dat het systeem heel strict getypeert is, wat in het geval van template functies eigenlijk helemaal niet het geval is.

Natuurlijk kun je door teveel types weg te laten onduidelijke code schrijven. Maar bij verstandig gebruik kun je juist helderdere code produceren doordat je irrelevante details weglaat.
pedorus schreef op dinsdag 09 februari 2010 @ 22:33:
In Google's nieuwe taal Go wordt ook een soort van var gebruikt [..]
Inderdaad. Dat bevalt me persoonlijk erg in Go. Een typisch for loopje vereist niet meer code dan:
Go:
1
2
3
for i := 1; i <= 10; i++ {
    // body
}

Je kunt het (equivalent) schrijven als:
Go:
1
2
3
for var i int = 1; i <= 10; i++ {
    // body
}

In het eerste voorbeeld mis je naar mijn idee niets (het is direct duidelijk dat i gewoon een integer is, zoals 9 van de 10 keer dat je een for-lusje schrijft) maar je voorkomt wel een hoop ruis die je in het tweede voorbeeld wel hebt. In Go is het voordeel groter dan in C# omdat je var juist gebruikt als je wél een type wil specificeren, dus in de korte vorm kun je zowel het var keyword als het type (int) weglaten. In C# zou je in een vergelijkbaar lusje het ene keyword (int) door het andere (var) kunnen vervanging, wat je weinig winst oplevert.

(Trade-off is overigens wel dat je in Go bij een variabele declaratie weer de initializer weg kunt laten, dus i := 0 of var i int zijn equivalent.)

Ik weet trouwens niet of mensen hier ervaring hebben met ML-gebaseerde talen (OCaml, F# en dergelijke)? Programmeurs hebben in die talen wel de neiging (naar mijn smaak) te weinig type-informatie achter te laten, omdat de compiler simpelweg krachtig genoeg is om praktisch overal (hoewel niet overal) het goede type bij te verzinnen. Dat is handig bij het definiëren van lokale functies (die meegegeven worden aan higher level functions als map en filter enzo) maar zo kun je een hele module schrijven zonder één type te noemen, en dat wordt mijns inziens toch lastig lezen. Ter vergelijking dwint Go je tenminste nog alle parameters en return types van functies en methoden te specificeren, zodat je als lezer enig houvast hebt zolang je een functie/methode in het geheel beschouwt.

PGP public key


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

RobIII schreef op woensdag 10 februari 2010 @ 01:37:
[...]

str-wat? :P
Jawel, tuurlijk geeft 't genoeg informatie als je er even een kopje koffie bij pakt en op je elfendertigste gaat zitten doorfietsen. Punt is dat var hier wat onhandig gedemonstreerd werd en het juist de leesbaarheid had bevorderd door char uit te schrijven. Dan had je het sneller (en zekerder) begrepen.
De moeite die het kost om te achterhalen wat het type is van een variabele verschilt van geval per geval. In de code van pedorus stond het type van de collectie 3 regels erboven.
For all you know is het een List<Stream> i.p.v. een string.
Dan had ik een naam als "strs" gebruikt om meervoud aan te geven. :p
Voor een 3-regel code voorbeeldje is 't nogal snel afgeleid natuurlijk. Voor wat complexere zaken kan dat natuurlijk heel anders liggen; mede afhankelijk van de duidelijkheid in naamgeving natuurlijk.
Zekers. Naar mate de omvang van de code groter wordt is het handiger als er meer informatie binnen handbereik is, i.p.v. heen en weer door je code te lopen om te achterhalen wat het type van een bepaalde variabele is. Naamgeving speelt hierbij een grote rol, maar ook zaken als het klein houden van je methodes.

* RayNbow is zelf van mening dat het type van de methode al genoeg informatie moet bieden over wat de methode doet. Graag zo min mogelijk type-informatie binnen de methode zelf. :p
Soultaker schreef op woensdag 10 februari 2010 @ 01:58:
Ik weet trouwens niet of mensen hier ervaring hebben met ML-gebaseerde talen (OCaml, F# en dergelijke)?
* RayNbow heeft ervaring met Haskell :p
Programmeurs hebben in die talen wel de neiging (naar mijn smaak) te weinig type-informatie achter te laten, omdat de compiler simpelweg krachtig genoeg is om praktisch overal (hoewel niet overal) het goede type bij te verzinnen. Dat is handig bij het definiëren van lokale functies (die meegegeven worden aan higher level functions als map en filter enzo) maar zo kun je een hele module schrijven zonder één type te noemen, en dat wordt mijns inziens toch lastig lezen. Ter vergelijking dwint Go je tenminste nog alle parameters en return types van functies en methoden te specificeren, zodat je als lezer enig houvast hebt zolang je een functie/methode in het geheel beschouwt.
In Haskell is het good-practice om bij top-level definities altijd het type te vermelden ter documentatie (desnoods door eerst de type checker te vragen wat het type is om 'm vervolgens te copy/pasten in je src file).

Addendum:
Soms vraag ik me wel af waarom we niet de definitie kunnen weglaten wanneer het type voldoet. Als ik bijv. alleen dit type opgeef
code:
1
(a -> (b -> c)) -> (b -> (a -> c))

zou de compiler toch slim genoeg moeten zijn om de implementatie (=bewijs voor dit type) te kunnen genereren? ;)

[Voor 33% gewijzigd door RayNbow op 10-02-2010 02:25]

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • cfern
  • Registratie: oktober 2009
  • Laatst online: 21-09 17:33
Ik leerde zelf eerst F# programmeren voor C#. Beetje vreemde volgorde, maar te verklaren: ik pakte F# iets meer dan een jaar geleden op als hobby toen ik op mijn werk nog aan VBA/VB.Net1.1 vast zat. Pas later kon ik meeprogrammeren aan C# projecten. In F# gaat de type inference nog een slag verder dan wat var doet, dus ik vond het gebruik van var in C# code allesbehalve vreemd en zelfs natuurlijk. Ik heb dus nooit enige weerstand gevoeld tegen var.

Telkens als ik dingen als 'var is toch hetzelfde als Variant in vba?' of 'var kost toch performance?' hoor moet ik mijn best doen om mijn bloeddruk laag te houden. Ik vind dat als de compiler eenduidig kan afleiden wat het type van een variabele is, dat dubbel opschrijven nergens voor nodig is.

Ik probeer op mijn werk zoveel mogelijk uit te leggen wat var wél doet, opdat mijn collega's er ook eens wat vaker gebruik van maken. Eerst voerde ik het gebruik van var uit tot het uiterste: ik hobbelde braaf achter Resharper aan en ook eenvoudige value types werden var bij mij. Ik schrijf nu eenvoudige (non-struct) value types gewoon uit.

Ik probeer wel bij een var zulke namen te kiezen dat de lezer ook nog eens het type zou kunnen afleiden (GeometryList, FilteredRows, etc.), maar dat heet geloof ik gewoon goede programmeeretiquette.

P.S.
Grappige(?) valkuil (waarschuwing: pedant voorbeeld):
C#:
1
2
3
var a = 2147483647;
var b = 2147483648;
var c = -b;

Drie declaraties, drie verschillende types.

"I'd rather have a full bottle in front of me, than a full frontal lobotomy." (Tom Waits) | PoE


  • Haan
  • Registratie: februari 2004
  • Laatst online: 22-09 10:26

Haan

dotnetter

Interessante discussie waar ik zelf ook weleens over nadenk (ik zie dat ik zelfs in gequote wordt :P ).
Ik ben het denk ik eens met wat de meerderheid hier lijkt te zeggen, dat het vooral bij generic collections een voordeel oplevert qua leesbaarheid.

Kater? Eerst water, de rest komt later
Last.fm profiel


  • BM
  • Registratie: september 2001
  • Laatst online: 20:12

BM

Moderator Spielerij
Ik ben het met de meeste bovenstaande mensen wel eens. Als echt extreem duidelijk is wat voor type er gebruikt word (new statement) heb ik weinig bezwaar tegen het gebruik van var, al vind ik voluit geschreven types alsnog ietsje duidelijker.
Bij loopjes als 'foreach(var x in y)' (slechte naamgeving alert ;)) is het imho not done, omdat het totaal niet duidelijk is wat er hier gebeurd.

Persoonlijk gebruik ik var eigenlijk alleen maar icm Linq. Verder tik ik alles gewoon uit zelfs als de typenamen wat langer worden.

@cfern: leuk voorbeeld.
a = integer
b = long
c = int?

Maakt toch maar 2 verschillende types? :?

X1 Gamercard | iRacing
Even the dark has a silver lining


  • Deathraven
  • Registratie: november 2001
  • Laatst online: 21-09 21:26
Ik vind het echt een gevalletje persoonlijk voorkeur. Ik gebruik het zelf om het werken met de wat langere type namen makkelijker te maken.
Verder vind ik naamgeving van variabelen vele malen belangrijker dan nadenken of ik ergens wel of niet var wil gebruiken.

Overigens al best wel wat mythes voorbij zien komen. Gelukkig werden deze al ontkracht door verschillende mensen. Mythes zoals dat het gebruik van var niet typesafe is of dat het je code langzamer maakt. Als ik zoiets lees vraag ik me af of je dan uberhaupt wel de definitie van het keyword hebt opgezocht :P
Al kan ik me best wel iets voorstellen bij de verwarring, er zijn zat andere talen waarbij het keyword var dus niet typesafe is.

  • cfern
  • Registratie: oktober 2009
  • Laatst online: 21-09 17:33
@BM: a is correct, b en c niet. C# pakt het meest beperkte datatype dat het gegeven getal kan bevatten. Vergeet niet dat er ook nog verschil is tussen signed en unsigned ;)

spoiler:
a = int, dat past net. b past niet niet in een int. Past het nog in 32 bits? Jawel, in een unsigned int. Past c in een int, nee, te groot. In een uint? Zeker niet, want negatief. Een long dan? Check.

[Voor 39% gewijzigd door cfern op 10-02-2010 10:17]

"I'd rather have a full bottle in front of me, than a full frontal lobotomy." (Tom Waits) | PoE


  • YopY
  • Registratie: september 2003
  • Laatst online: 13:57
Ik dacht eerst (ben geen C# expert) dat var een soort van dynamische taal van C# maakt, waar ik geen fan van ben. Maar dat lijkt mee te vallen, nu ik dit topic lees. Het lijkt me ideaal voor variabelen met een kleine scope (zoals generics met een lange naam), wat dat aangaat zou ik het ook wel in Java willen hebben.

Zou het echter niet graag in class variabelen of parametertypes willen zien. Maar voor hetzelfde kan dat ook helemaal niet.

  • BM
  • Registratie: september 2001
  • Laatst online: 20:12

BM

Moderator Spielerij
cfern schreef op woensdag 10 februari 2010 @ 09:58:
@BM: a is correct, b en c niet. C# pakt het meest beperkte datatype dat het gegeven getal kan bevatten. Vergeet niet dat er ook nog verschil is tussen signed en unsigned ;)

spoiler:
a = int, dat past net. b past niet niet in een int. Past het nog in 32 bits? Jawel, in een unsigned int. Past c in een int, nee, te groot. In een uint? Zeker niet, want negatief. Een long dan? Check.
spoiler:
Ah, unsinged int hebben we ook nog. Maar even voor mijn idee, -2147483648 pas toch prima in een int? Of zie ik nu wat anders over het hoofd? :?
YopY schreef op woensdag 10 februari 2010 @ 10:51:
Zou het echter niet graag in class variabelen of parametertypes willen zien. Maar voor hetzelfde kan dat ook helemaal niet.
Afaik kun je var idd niet als parameter of returnvalue gebruiken. De aanroepende partij weet op dat moment namelijk niet wat ie terug kan verwachten.

[Voor 22% gewijzigd door BM op 10-02-2010 10:53]

X1 Gamercard | iRacing
Even the dark has a silver lining


  • user109731
  • Registratie: maart 2004
  • Niet online
De literal -2147483648 mag wel in C# als uint, maar dat is een uitzondering. Normaal levert de minus operator op een uint altijd een long op:
If the operand of the negation operator is of type uint, it is converted to type long, and the type of the result is long. An exception is the rule that permits the int value −2147483648 (−231) to be written as a decimal integer literal (Section 2.4.4.2).
code:
1
2
3
4
5
6
7
Mono C# Shell, type "help;" for help

Enter statements below.
csharp> uint x = 10;
csharp> var y = -x;
csharp> y.GetType();
System.Int64

Hmm, dat zou in bepaalde gevallen een nadeel kunnen zijn van var. Hoewel long vs. int in 99% van de C#-applicaties ook niet heel spannend is.

[Voor 8% gewijzigd door user109731 op 10-02-2010 11:07]


  • The Flying Dutchman
  • Registratie: mei 2000
  • Laatst online: 21-09 13:11
.oisyn schreef op dinsdag 09 februari 2010 @ 23:04:
Als je het niet erg vindt behandel ik dit even als een algemeen static type inference topic, en gaat het dus ook op voor vergelijkbare features in andere talen zoals "auto" in C++0x :)

Het is voornamelijk bedoeld om nutteloze verbositeit te voorkomen. Iets als "var stringList = new List<string>()" ben ik helemaal voor, compleet overbodig om voor stringList nog een keer het type te specificeren terwijl dat wel duidelijk is uit de new. Ook is het handig bij functies die een wat complexere generic/template types retourneren. Iet als "std::map<int, std::vector<float>>::iterator it = myMap.find(42);" tikt ook wat onhandig. Nou zijn daar nog typedefs voor in C++ (kent C# geloof ik niet?), maar die lossen het probleem slechts deels op. Hier maak je feitelijk de afweging tussen verbeterde productiviteit en het verlies van informatie in het stuk code.

Dat betekent dat je het ook kunt overdrijven, zoals je laat zien in dat voorbeeld, maar ook een beetje in het stukje code wat je eerder vandaag geplaatst hebt waar imho, even afgezien van het misverstand van de betekenis van 'var', terechte kritiek op kwam :). Bij dingen als "foreach (var c in str)" had ik toch liever "char" gelezen. Met het gebruik van "var" win je geen drol, maar je verliest wel een klein beetje aan informatie.
Volledig mee eens, maar ik ben dan ook een die-hard C++'er die heel erg van strict typing houdt ;). Het gaat om leesbaarheid van code, een deel van de leesbaarheid zit in de informatie die je geeft. Door gebruik van `var' haal je een stukje informatie weg terwijl je door `var' te gebruiken in veel gevallen maar heel weinig wint qua hoeveelheid typwerk. De voorbeelden die .oisyn noemt zijn weer prima voorbeelden van waar je juist wél wat kunt winnen door `var' (of in het geval van c++0x `auto') te gebruiken.

The Flying Dutchman


  • sig69
  • Registratie: mei 2002
  • Laatst online: 00:31
Het argument dat je niet twee keer de hele type declaration hoeft te typen gaat overigens niet altijd op, of ik nu
C#:
1
List<string> l = new <enter> // wordt afgemaakt door intellisense

type of
C#:
1
var l = new List<string>();

Wat is langer?

  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

JanDM schreef op woensdag 10 februari 2010 @ 11:02:
De literal -2147483648 mag wel in C# als uint, maar dat is een uitzondering. Normaal levert de minus operator op een uint altijd een long op:
Idd, de comment van cfern dat de waarde 'te groot is' gaat bij c dan ook helemaal niet op. Nou kan de compiler evenwel nog de grootte inferren (die kwam immers van een constante), maar dat doet ie niet, omdat het geen constante is maar een variabele.
sig69 schreef op woensdag 10 februari 2010 @ 12:30:
Het argument dat je niet twee keer de hele type declaration hoeft te typen
Het gaat alleen niet louter om typen. Je leest het type ook dubbelop. En bij het bewerken van die ene regel zul je ook meer moeite moeten doen.

[Voor 24% gewijzigd door .oisyn op 10-02-2010 12:43]

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • Grijze Vos
  • Registratie: december 2002
  • Laatst online: 18-09 23:10
BM schreef op woensdag 10 februari 2010 @ 09:37:
Bij loopjes als 'foreach(var x in y)' (slechte naamgeving alert ;)) is het imho not done, omdat het totaal niet duidelijk is wat er hier gebeurd.
Ik vind loopjes juist bij uitstek de plek om dit te doen.

C#:
1
2
3
4
List<NewsArticle> articles = News.GetArticles();
foreach(var article in articles)
{ // doe iets
}

Hartstikke leesbaar.
Hier declareer ik wel het type van de lijst, omdat die uit een externe functie komt.

[Voor 10% gewijzigd door Grijze Vos op 10-02-2010 13:03]

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


  • whoami
  • Registratie: december 2000
  • Laatst online: 20:44
YopY

Zou het echter niet graag in class variabelen of parametertypes willen zien. Maar voor hetzelfde kan dat ook helemaal niet.
Neen, dat kan inderdaad niet.
Als je 'var' gebruikt, moet je die variable bij declaratie ook direct initializeren, zodanig dat de compiler kan weten welk type die variable nu eigenlijk is.

In principe zou je dan nog kunnen stellen dat het mogelijk moet zijn om 'var' te gebruiken voor member variables, als je die direct instantieert, maar dat wordt verhinderd:

code:
1
2
3
4
public class Test
{
    public var i = 5;
}


resulteert in:
The contextual keyword 'var' may only appear within a local variable declaration
sig69 schreef op woensdag 10 februari 2010 @ 12:30:
Het argument dat je niet twee keer de hele type declaration hoeft te typen gaat overigens niet altijd op, of ik nu
C#:
1
List<string> l = new <enter> // wordt afgemaakt door intellisense

type of
C#:
1
var l = new List<string>();

Wat is langer?
Het gaat niet over het 'typen' van die code, maar over het lezen ervan, IMHO.
wat .oisyn dus al zegt.

[Voor 25% gewijzigd door whoami op 10-02-2010 14:01]


  • pedorus
  • Registratie: januari 2008
  • Niet online
Soultaker schreef op woensdag 10 februari 2010 @ 01:58:
Ter vergelijking dwint Go je tenminste nog alle parameters en return types van functies en methoden te specificeren, zodat je als lezer enig houvast hebt zolang je een functie/methode in het geheel beschouwt.
Er is ook een Ruby-achtige statically typed .NET-taal waar dat niet meer nodig is: Boo. Functies en properties krijgen een type aan de hand van hun returns of hun initialisatie, en ik kan me voorstellen dat ze voor parameters generics gaan gebruiken. Het probleem dat ik daar zie ontstaan is dat je al snel niet meer snapt voor welke types een functie nu eigenlijk bedacht is, en dat zal je toch sowieso ergens moeten gaan documenteren dan (als het serieuze code is). Daarnaast werkt het nogal een vreemde bottom-up approach in de hand om functiedefinities af te laten hangen van wat er uiteindelijk geretourneerd wordt - dit werkt niet met stub-methodes van het type 'throw new NotImplementedException();'. Het hele idee van 'wrist friendly' snap ik dus niet zo op dat punt. Aan de andere kant kun je wel expliciet de types opgeven bij de functiedefinities. C#'s var kun je alleen gebruiken voor locale variabelen (zie boven), dus daar speelt dit probleem veel minder tot niet.
sig69 schreef op woensdag 10 februari 2010 @ 12:30:
Het argument dat je niet twee keer de hele type declaration hoeft te typen gaat overigens niet altijd op, of ik nu
C#:
1
List<string> l = new <enter> // wordt afgemaakt door intellisense

type of
C#:
1
var l = new List<string>();

Wat is langer?
Zoals gezegd is leesbaarheid een stuk belangrijker op termijn; anders zou je de documentatie ook wel weg kunnen laten, dat bespaart pas tikwerk... ;) Maar het is ook een bepaald denkproces. Ik bedenk eerst dat ik voor iets een variabele nodig heb, en dan pas wat voor type daar dan het beste bij past. Oftwel, het laatste loopt synchromer op, en kan zo toch weer een aantal milliseconden schelen. :p Het kan trouwens ook nog komen omdat ik redelijk wat Delphi-ervaring heb (en daar doe je var i : Integer; maar verder is het concept dat je variabelen in een apart stukje declareert niet al te handig).
Grijze Vos schreef op woensdag 10 februari 2010 @ 13:01:
[...]

Ik vind loopjes juist bij uitstek de plek om dit te doen.

C#:
1
2
3
4
List<NewsArticle> articles = News.GetArticles();
foreach(var article in articles)
{ // doe iets
}

Hartstikke leesbaar.
Hier declareer ik wel het type van de lijst, omdat die uit een externe functie komt.
Het lijkt me in deze code eigenlijk totaal niet boeiend of GetArticles() nou bijvoorbeeld een List, IList, IEnumerable of Array teruggeeft, en of dit later nog wijzigt. var dus op regel 1 wat mij betreft. :9 Een beetje afhankelijk van of het type van NewsArticle bijzonder is zou ik dan in regel 2 eventueel wel het type uitschrijven, maar waarschijnlijk boeit dat ook niet.

Vitamine D tekorten in Nederland | Corona: wat niet gepost kan worden


  • MrBucket
  • Registratie: juli 2003
  • Laatst online: 27-05-2016
Er is naar mijn idee maar 1 reden om 'var' te gebruiken, en dat is als je gebruik maakt van anonymous types - die hebben geen typenaam en dus zul je wel 'var' moeten gebruiken:
C#:
1
2
3
4
5
6
7
8
var productQuery = 
    from prod in products
    select new { prod.Color, prod.Price };

foreach (var v in productQuery)
{
    Console.WriteLine("Color={0}, Price={1}", v.Color, v.Price);
}

Daarnaast zou je voor hele complexe returntypes (uit bijv. Linq-statements) ervoor kunnen kiezen om 'var' te verkiezen boven het uitschrijven van het type om de code minder rommelig te maken.

In alle andere situaties is het imo gewoon gemakszucht en maak je de code onnodig moeilijk leesbaar door typeinformatie bewust weg te laten.

  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

In alle andere situaties is het imo gewoon gemakszucht en maak je de code onnodig moeilijk leesbaar door typeinformatie bewust weg te laten.
Nou idd joh, de weggehaalde informatie uit deze regel code is echt onmisbaar
C#:
1
var stringList = new List<string>();

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • Soultaker
  • Registratie: september 2000
  • Laatst online: 25-07 13:55
Als je heel conservatief wil var'en lijkt me inderdaad dat je het type weg kan laten bij variabelen die direct geïnitialiseerd worden met een constructor, maar 'm bijvoorbeeld wel laten als je initializer ingewikkelder is (b.v. een functie call). Overigens is stringList natuurlijk een beetje lamme variabelenaam; in het echt geef je daar een zinnigere naam aan, die het preciese type wellicht niet direct verraadt.

Overigens heeft C++ het (ten opzichte van Java en C#) wel goed geregeld dat je de constructornaam weg kunt laten als je een variabele direct initialiseert:
C++:
1
2
3
std::string str(buf, len);
// mooier dan:
std::string str = std::string(buf, len);

Dat is eigenlijk hetzelfde maar dan vanaf de andere kant aangepakt.

[Voor 21% gewijzigd door Soultaker op 10-02-2010 21:23]

PGP public key


  • MrBucket
  • Registratie: juli 2003
  • Laatst online: 27-05-2016
.oisyn schreef op woensdag 10 februari 2010 @ 21:01:
[...]

Nou idd joh, de weggehaalde informatie uit deze regel code is echt onmisbaar
C#:
1
var stringList = new List<string>();
En nu dit fragment:
C#:
1
var klanten = getKlanten();

Wat heb ik nu teruggekregen?

  • YopY
  • Registratie: september 2003
  • Laatst online: 13:57
sig69 schreef op woensdag 10 februari 2010 @ 12:30:
Het argument dat je niet twee keer de hele type declaration hoeft te typen gaat overigens niet altijd op, of ik nu
C#:
1
List<string> l = new <enter> // wordt afgemaakt door intellisense

type of
C#:
1
var l = new List<string>();

Wat is langer?
De eerste, als het volledig uitgeschreven wordt ;). Ik ben persoonlijk ook van mening dat goed duidelijk en leesbare code belangrijker is dan code dat je snel kunt schrijven. Ligt er een beetje aan waar je mee bezig bent natuurlijk (voor prototyping enzo is snel iets werkbaars neerzetten weer belangrijker), maar ik hou meer van de 'verbose' categorie.

Een programmeertaal die je in steno kunt typen om met een druk op de knop volledig uitgeschreven te worden zou echter wel leuk zijn. Ik typ een

code:
1
for 1 to 10 dosomething


in, en de 'steno-compiler' maakt er een net

code:
1
2
3
for (int i = 1; i < 10; i++) {
   this.doSomething();
}


van. Snel typen, langzame code :Y).

(Maar waarschijnlijk is er al een programmeertaal waar je snel zooi in kunt typen zonder leestekens of IntelliSense of auto-aanvullen van haakjes en tags (dat, om de een of andere manier, nooit lekker werkt voor mij - zit nog te vaak met de pijltjestoetsen en backspace dingen te doen).

  • RobIII
  • Registratie: december 2001
  • Laatst online: 00:20

RobIII

Admin Devschuur®

^ Romeinse 3 ja!

MrBucket schreef op woensdag 10 februari 2010 @ 21:48:
[...]

En nu dit fragment:
C#:
1
var klanten = getKlanten();

Wat heb ik nu teruggekregen?
Smaken verschillen, maar het is al eens gezegd:
pedorus schreef op woensdag 10 februari 2010 @ 14:50:
Het lijkt me in deze code eigenlijk totaal niet boeiend of GetArticlesgetKlanten() nou bijvoorbeeld een List, IList, IEnumerable of Array teruggeeft, en of dit later nog wijzigt. var dus op regel 1 wat mij betreft. :9

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Roses are red Violets are blue, Unexpected ‘{‘ on line 32.

Over mij


  • MrBucket
  • Registratie: juli 2003
  • Laatst online: 27-05-2016
RobIII schreef op woensdag 10 februari 2010 @ 22:05:
[...]

Smaken verschillen, maar het is al eens gezegd:

[...]
Er vanuitgaande dat het uberhaupt een collectie is, en niet een DataTable ofzo. En wat zit er dan in die collectie? Klanten, strings, object[], ...?

Ik blijf erbij dat het gebruik van 'var' in 9 van de 10 gevallen totaal geen meerwaarde biedt, maar wel het risico op het schrijven van slecht leesbare/onderhoudbare code vergroot.

  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

MrBucket schreef op woensdag 10 februari 2010 @ 21:48:
[...]

En nu dit fragment:
C#:
1
var klanten = getKlanten();

Wat heb ik nu teruggekregen?
.oisyn in "\[C#][discussie] Lekker veel var gebruiken?" :
Ook is het handig bij functies die een wat complexere generic/template types retourneren. Iet als "std::map<int, std::vector<float>>::iterator it = myMap.find(42);" tikt ook wat onhandig. [..] Hier maak je feitelijk de afweging tussen verbeterde productiviteit en het verlies van informatie in het stuk code.
Maar waar ik op reageerde is deze opmerking:
Er is naar mijn idee maar 1 reden om 'var' te gebruiken, en dat is als je gebruik maakt van anonymous types
Dus ik kwam met een tegenvoorbeeld. Kun jij wel weer met weer een ander tegenvoorbeeld komen, maar dat is niet relevant. Bottom line is dat je uitspraak imho onjuist is, en je het volgens mij stiekem gewoon met mij eens bent (maar het gewicht dat je toekent aan "verlies van informatie" blijft natuurlijk persoonlijk)

[Voor 7% gewijzigd door .oisyn op 10-02-2010 23:07]

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • pedorus
  • Registratie: januari 2008
  • Niet online
YopY schreef op woensdag 10 februari 2010 @ 22:02:
De eerste, als het volledig uitgeschreven wordt ;).
:D
Een programmeertaal die je in steno kunt typen om met een druk op de knop volledig uitgeschreven te worden zou echter wel leuk zijn. Ik typ een

code:
1
for 1 to 10 dosomething


in, en de 'steno-compiler' maakt er een net

code:
1
2
3
for (int i = 1; i < 10; i++) {
   this.doSomething();
}


van. Snel typen, langzame code :Y).
Ehm, zelfs in een volkomen standaardinstallatie van VS.NET zit een code snipped voor 'for', dus dit krijg je met "for[tab][tab][tab]10[enter]do..." Meestal zijn zelfs die "o" en "r" niet nodig, en "this." lijkt me niet echt nuttig in dit verband. ;) Overigens moet je als je exact dit wilt nog wel even de standaard '0' in een '1' veranderen later, want dit is een vrij bijzondere for-loop.
MrBucket schreef op woensdag 10 februari 2010 @ 22:20:
[...]

Er vanuitgaande dat het uberhaupt een collectie is, en niet een DataTable ofzo. En wat zit er dan in die collectie? Klanten, strings, object[], ...?

Ik blijf erbij dat het gebruik van 'var' in 9 van de 10 gevallen totaal geen meerwaarde biedt, maar wel het risico op het schrijven van slecht leesbare/onderhoudbare code vergroot.
Ik ben sterk voor informatie op het scherm. Maar dit lijkt me data waar je toch niks mee gaat doen, en die dus beter weggefilterd had kunnen worden. Als je het type wil weten, ondanks dat er var staat, hoef je alleen maar even je muiscursor erboven te zetten (zonder IDE lukt dat enkel niet natuurlijk). In sommige gevallen is het wel handig als je het type direct zonder enige moeite kan zien, bijvoorbeeld bij de gegeven bool en char voorbeelden hierboven. Dat lijkt mij bij een GetKlanten() in zijn algemeenheid niet aan de orde, want uit de naam blijkt duidelijk dat het een verzameling betreft. Kun je de rest van de context geven waardoor het wel nuttige informatie blijkt te zijn, die terecht schermruimte/leestijd inneemt? :)

Vitamine D tekorten in Nederland | Corona: wat niet gepost kan worden


  • whoami
  • Registratie: december 2000
  • Laatst online: 20:44
MrBucket schreef op woensdag 10 februari 2010 @ 21:48:
[...]

En nu dit fragment:
C#:
1
var klanten = getKlanten();

Wat heb ik nu teruggekregen?
Even met de mousepointer erover hoveren, en intellisense zegt het je. :P

  • Soultaker
  • Registratie: september 2000
  • Laatst online: 25-07 13:55
Dat vind ik ook een slecht standpunt, eerlijk gezegd. Code hoort in principe leesbaar te zijn zonder allerlei externe tools voor annotatie of formatting. Dat wil niet zeggen dat je geen tools mag gebruiken, maar als ze essentieel zijn voor het begrip is de code gewoon slecht geschreven.

Ik print ook code graag uit om die in detail te bestuderen. Toegegeven, dan gaat het wel om wat complexere code dan een website of een GUI frontend, maar je hebt dan geen Intellisense om je te helpen. Het is dan wel essentieel dat de code voor zich spreekt.

PGP public key


  • Nick_S
  • Registratie: juni 2003
  • Laatst online: 22-09 11:52

Nick_S

++?????++ Out of Cheese Error

.oisyn schreef op dinsdag 09 februari 2010 @ 23:04:
...Iets als "var stringList = new List<string>()" ben ik helemaal voor...
Ik denk dat het een voorkeurs kwestie is, maar ik zie liever de declaratie als compleet en de manier van instantieren moet het daarvan maar afleiden. De Google Collections API voor Java doet het wat mij betreft erg netjes:
Java:
1
List<String> listOfStrings = Lists.newArrayList();


Heel mooi gescheiden wat het is (List<String>) en hoe het geimplementeerd is (een ArrayList). Ook de extra mogelijkheden van deze API zijn erg mooi.

Java:
1
List<String> listOfStrings = Lists.newArrayList("String 1" , "String 2", "Another String");


En de topper uit deze API is voor mij nog altijd de MultiMap. Een Map (key, value paar) waarbij aan een key meerdere values kunnen hangen.

'Nae King! Nae quin! Nae Laird! Nae master! We willna' be fooled agin!'


  • YakuzA
  • Registratie: maart 2001
  • Laatst online: 00:32

YakuzA

Wat denk je nou zelluf hey :X

Grijze Vos schreef op woensdag 10 februari 2010 @ 13:01:
[...]

Ik vind loopjes juist bij uitstek de plek om dit te doen.

C#:
1
2
3
4
List<NewsArticle> articles = News.GetArticles();
foreach(var article in articles)
{ // doe iets
}

Hartstikke leesbaar.
Hier declareer ik wel het type van de lijst, omdat die uit een externe functie komt.
Eerlijk gezegd vind ik in dit voorbeeld zelfs de var overbodig, door de naamgeving is ook dit nog duidelijk namelijk:
C#:
1
2
3
4
List<NewsArticle> articles = News.GetArticles();
foreach(article in articles)
{ // doe iets
}

(niet dat dit compileert, maar gaat om het idee dat als je iets uit een strongtyped list haalt, dit alleen een 'NewsArticle' kan zijn)

[Voor 8% gewijzigd door YakuzA op 11-02-2010 10:37]

Death smiles upon us all, all a man can do is smile back.
PSN


  • mOrPhie
  • Registratie: september 2000
  • Laatst online: 19-09 13:09

mOrPhie

denniebee

Soultaker schreef op donderdag 11 februari 2010 @ 00:50:
Dat vind ik ook een slecht standpunt, eerlijk gezegd. Code hoort in principe leesbaar te zijn zonder allerlei externe tools voor annotatie of formatting.
Mjah, dat is misschien bij veel talen zo, maar bij .net (uitgezonderd een aantal mono-developers) is het zo dat je voornamelijk in visual studio werkt en je dus intellisense hebt. Ja, toegegeven, het voorbeeld dat aangehaald wordt zou ik persoonlijk ook anders doen, maar in praktische zin zou je kunnen stellen dat het in de meeste gevallen volstaat om op de IDE te vertrouwen.

Ik gebruik zelf nog zelden var overigens. Niet omdat ik er tegen ben, maar omdat ik het altijd al gewend was zonder var te werken. In mijn geval is het zo dat het echte coden misschien zo weinig tijd in beslag neemt (ten opzichte van denken/bedenken) dat het vrij weinig uit maakt of ik List<string> typ of var. Veel wordt toch door Visual Studio al versneld.

https://tellick.nl/


  • Snake
  • Registratie: juli 2005
  • Laatst online: 23:29

Snake

Los Angeles, CA, USA

Soultaker schreef op woensdag 10 februari 2010 @ 21:21:
C++:
1
2
3
std::string str(buf, len);
// mooier dan:
std::string str = std::string(buf, len);

Dat is eigenlijk hetzelfde maar dan vanaf de andere kant aangepakt.
Schiet niet op mij, maar wordt de ene niet op de stack gealloceerd, en de andere op de heap? :$

Going for adventure, lots of sun and a convertible! | GMT-8


  • RobIII
  • Registratie: december 2001
  • Laatst online: 00:20

RobIII

Admin Devschuur®

^ Romeinse 3 ja!

Nick_S schreef op donderdag 11 februari 2010 @ 01:19:
En de topper uit deze API is voor mij nog altijd de MultiMap. Een Map (key, value paar) waarbij aan een key meerdere values kunnen hangen.
Dus een Dictionary<T, List<T>> :? :Y) :P
Of zelfs Dictionary<T, Dictionary<T, T>> :P

[Voor 11% gewijzigd door RobIII op 11-02-2010 11:42]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Roses are red Violets are blue, Unexpected ‘{‘ on line 32.

Over mij


  • ctor
  • Registratie: augustus 2009
  • Laatst online: 02-08-2012

ctor

Dormito ergo sum

Snake schreef op donderdag 11 februari 2010 @ 11:30:
[...]

Schiet niet op mij, maar wordt de ene niet op de stack gealloceerd, en de andere op de heap? :$
Nee, kort door de bocht: Om op de heap te allocaten (Dunglish) moet je: Type* t = new Type(); gebruiken, voor de stack Type t2.

When I had journeyed half of our life's way, I found myself within a shadowed forest, for I had lost the path that does not stray.


  • Snake
  • Registratie: juli 2005
  • Laatst online: 23:29

Snake

Los Angeles, CA, USA

ctor schreef op donderdag 11 februari 2010 @ 11:44:
[...]

Nee, kort door de bocht: Om op de heap te alllocaten (??) moet je: Type* t = new Type(); gebruiken, voor de stack Type t2.
Ik ga het echt nooit doorkrijgen hoe dat werkt in c++

Overigens: ik programmeer in C# vaak met var. Maar dat is gewoon omdat ik lui ben. Met R# laat ik altijd var vervangen door het juiste typen.

Maar wat veel mensen denken: var is niet dynamic. Dwz: als de compiler niet 1 type kan afleiden dan zal hij een error geven, dit itt dynamic in .NET 4.0

Going for adventure, lots of sun and a convertible! | GMT-8


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

Nick_S schreef op donderdag 11 februari 2010 @ 01:19:
[...]


Ik denk dat het een voorkeurs kwestie is, maar ik zie liever de declaratie als compleet en de manier van instantieren moet het daarvan maar afleiden. De Google Collections API voor Java doet het wat mij betreft erg netjes:
Java:
1
List<String> listOfStrings = Lists.newArrayList();
Hoe werkt dat in hemelsnaam? Hoe weet newArrayList() hier dat hij een list van Strings moet maken, en niet eentje van Personen?
En de topper uit deze API is voor mij nog altijd de MultiMap. Een Map (key, value paar) waarbij aan een key meerdere values kunnen hangen.
Ah, je bedoelt dat ding dat al decennia bestaat in C++ :Y)

[Voor 9% gewijzigd door .oisyn op 11-02-2010 11:54]

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • evidoth
  • Registratie: september 2005
  • Laatst online: 07-04-2017
.oisyn schreef op donderdag 11 februari 2010 @ 11:54:
[...]

Hoe werkt dat in hemelsnaam? Hoe weet newArrayList() hier dat hij een list van Strings moet maken, en niet eentje van Personen?
Lijkt me wel duidelijk als je de signatuur van die methode ziet:
static <E> ArrayList<E> newArrayList(E... elements)


edit1:
Sorry, had niet gezien dat je het had op de versie zonder argumenten, maar dan vermoed ik dat het gewoon is dat voor java generics enkel compiletime informatie is. Je krijgt gewoon namelijk gewoon een warning bij die assignment over unchecked / unsafe operations.

edit2:
Ik heb het nog even nagekeken, en als je dat type methode oproept zonder argumenten wordt er gewoon een Object[] array meegegeven (vast leeg dan), dus het return type is dan ArrayList<Object>.

[Voor 42% gewijzigd door evidoth op 11-02-2010 12:24]


  • ctor
  • Registratie: augustus 2009
  • Laatst online: 02-08-2012

ctor

Dormito ergo sum

offtopic:
[quote]Snake schreef op donderdag 11 februari 2010 @ 11:46:
[...]

Ik ga het echt nooit doorkrijgen hoe dat werkt in c++

[/quote]
Wanneer gebruik je de heap en wanneer de stack bedoel je?
Er zijn een paar dingetjes om rekening me te houden (en vast nog wel meer dan wat ik hier neerplemp)
- Weet je compile time niet waar naar verwezen wordt kun je geen reference (&) gebruiken, want een reference moet altijd ergens naar toe verwijzen terwijl een pointer NULL kan zijn. Dit kom je tegen in een overervingssituatie. Je hebt een class A, waarvan class B en C kinderen zijn. compile time weet je niet of A* a = new B() of A* a = new C();. Je hebt hier een pointer nodig.
- Aangezien je de pointer zou moeten deleten (of delete[] bij array) heb je kans op een memory leak, prefereer dus het alloceren op de stack (Type t, aan te roepen met t.<member>), deze wordt automagisch voor je schoongemaakt. De destructor wordt automatisch aangeroepen wanneer ze out of scope gaan.
- Objecten bij reference doorsturen, dus je functievoorschriften zien er zo uit: Class::Method(const Henk& h, const Miep& m), op deze manier geef je dus adressen door en maak je geen local copy van het object.
Of je m & h in de caller nou op de heap of stack hebt gealloceerd maakt niet uit, zolang ze niet out of scope gaan. Heb je ze verder niet nodig, op de stack doen, kopzorg minder.

Het is dus zinnig om na te denken over object life time (remember, je hebt geen GC) voor je een object alloceert op de heap of stack (en niet vergeten te delete([]) n indien nodig).

maar er zijn vast tweakers die er een stuk meer over kunnen vertellen in een apart topic, want stiekem ben ik best off-topic gegaan

[Voor 4% gewijzigd door ctor op 11-02-2010 12:16]

When I had journeyed half of our life's way, I found myself within a shadowed forest, for I had lost the path that does not stray.


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

evidoth schreef op donderdag 11 februari 2010 @ 12:06:
Sorry, had niet gezien dat je het had op de versie zonder argumenten, maar dan vermoed ik dat het gewoon is dat voor java generics enkel compiletime informatie is. Je krijgt gewoon namelijk gewoon een warning bij die assignment over unchecked / unsafe operations.
Ah, je moet dus eigenlijk dit doen:
Java:
1
List<String> list = Lists.newArrayList<String>();

Het blijft dubbelop.

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • NetForce1
  • Registratie: november 2001
  • Laatst online: 15-09 21:31

NetForce1

(inspiratie == 0) -> true

.oisyn schreef op donderdag 11 februari 2010 @ 12:20:
[...]

Ah, je moet dus eigenlijk dit doen:
Java:
1
List<String> list = Lists.newArrayList<String>();

Het blijft dubbelop.
Nee, dat kan gewoon zijn:
Java:
1
List<String> list = Lists.newArrayList();

dat kan de compiler voor je uitvogelen, maar hierbij gaat dat dan weer niet helaas (daar is dus die static methode voor verzonnen):
Java:
1
List<String> list = new ArrayList<String>();

De wereld ligt aan je voeten. Je moet alleen diep genoeg willen bukken...
"Wie geen fouten maakt maakt meestal niets!"


  • evidoth
  • Registratie: september 2005
  • Laatst online: 07-04-2017
.oisyn schreef op donderdag 11 februari 2010 @ 12:20:
[...]

Ah, je moet dus eigenlijk dit doen:
Java:
1
List<String> list = Lists.newArrayList<String>();

Het blijft dubbelop.
Nee, dat soort syntax bestaat vreemdgenoeg niet, het is:
Java:
1
List<String> list = Lists.<String>newArrayList();

Wat ikzelf alles behalve mooie syntax vind en het is zeker dubbelop.

[Voor 8% gewijzigd door evidoth op 11-02-2010 12:34]


  • evidoth
  • Registratie: september 2005
  • Laatst online: 07-04-2017
NetForce1 schreef op donderdag 11 februari 2010 @ 12:31:
[...]

Nee, dat kan gewoon zijn:
Java:
1
List<String> list = Lists.newArrayList();

dat kan de compiler voor je uitvogelen, maar hierbij gaat dat dan weer niet helaas (daar is dus die static methode voor verzonnen):
Java:
1
List<String> list = new ArrayList<String>();
De compiler kan het tweede zeker wel, die static methode is er gewoon voor eenvoudige aanmaken van voorafgevulde lists, zonder ofwel een tussenstap te maken naar arrays, ofwel een aparte add statement te voorzien voor elk element.

  • o0oPhreako0o
  • Registratie: augustus 2008
  • Laatst online: 17-03-2018
Wat ik vind van 'var';
Ik probeer het gebruik ervan te vermijden, om onduidelijkheden te voorkomen.

Voorbeeldje;
C#:
1
2
3
4
var waarde = 10;

//Iemand komt 'waarde' tegen in de code, en denkt;  "uhhh.. en wat is het nou ?  int16,int32,int64 ?
//Wat ga ik hiermee doen ?"

C#:
1
2
3
4
var klantnaam = "phreak";
var bedrijfsnaam = "micros0ft";

//Wat is het voordeel van var hier ?, gebruik dan gewoon  string


*Voorbeeldje dat hier stond was fout.. excuses! :P*

[Voor 25% gewijzigd door o0oPhreako0o op 11-02-2010 13:14. Reden: foutje ! :$]

#phreak


  • BM
  • Registratie: september 2001
  • Laatst online: 20:12

BM

Moderator Spielerij
Je laatste voorbeeld is in C# ook gewoon niet mogelijk :)
niet meer van toepassing, bedankt voor het aanpassen :)

[Voor 35% gewijzigd door BM op 11-02-2010 13:25]

X1 Gamercard | iRacing
Even the dark has a silver lining


  • evidoth
  • Registratie: september 2005
  • Laatst online: 07-04-2017
o0oPhreako0o schreef op donderdag 11 februari 2010 @ 12:42:
[/code]
C#:
1
2
3
4
5
6
public void berekening(var waarde)
{
//Calculatie....
}

berekening(waarde);   // Tja, wat wordt er verwacht ?, string ?.. neeeeee....  mischien een int32 ?
Deze mag dan ook niet, var mag enkel voorkomen als lokale variabele declaratie, maar met het dynamic keyword in C# 4.0 gaat dit wel.

[Voor 6% gewijzigd door evidoth op 11-02-2010 12:52]


  • pedorus
  • Registratie: januari 2008
  • Niet online
Die eerste: tsja, je moet toch wel snappen dat 10 een int is en 10L een long is als programmeur? Wellicht voor mensen die wat onwennig zijn met c# dan, maar ik zie geen grote problemen. Die tweede: strings zo initialiseren is sowieso bijna altijd testcode, var is 2 karakters korter en makkelijker te wijzigen. Die derde: compileert niet. Hier zeg ik dat het me ook in de meeste gevallen geen goed idee lijkt om wel zoiets te gaan hebben. :)
Nick_S schreef op donderdag 11 februari 2010 @ 01:19:
Java:
1
List<String> listOfStrings = Lists.newArrayList("String 1" , "String 2", "Another String");
Persoonlijk vind ik dit toch mooier:
C#:
1
var listOfStrings = new List<string> { "String 1", "String 2", "Another String" };

En het idee van interfacenaam a = new implementatie() is leuk in theorie, maar het lijkt me voor lokale variabelen wat onzinnig. In de praktijk komt het zelden voor dat je een andere implementatie zal kiezen dan een ArrayList, en dan nog hoef je in beide gevallen evenveel aan te passen. Sterker nog, misschien wil je later eigenlijk wel een generator/ienumerable ipv een lijst, en dan heb je geen List-interface meer. Het trekt ook niet zomaar door naar List<List<String>>.
Nou heb ik hier ook een aparte implementatie voor (zodat bijvoorbeeld de hash altijd 1x berekend wordt, hoewel Google's versie dat niet doet), maar op zich kun je inderdaad die structuur met 1 extentie-methode hetzelfde gebruiken als een multimap:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
            var d = new Dictionary<string, List<string>>();
            d.Put("test", "test1");
            d.Put("test", "test2");

//werkt gewoon prima met een extentiemethode zoals:
    public static void Put<TKey, TValue> (this IDictionary<TKey, List<TValue>> d, 
            TKey key, TValue value)
        {
            List<TValue> elem;
            if (d.TryGetValue(key, out elem)) elem.Add(value);
            else d[key] = new List<TValue>() { value };
        }

Het lijkt mij duidelijker om dit niet zo te schrijven, wat zonder type interference nodig zou zijn:
C#:
1
2
        Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
        d.Put<string, string>("test", "test1");

Zo zie je maar weer hoe krachtig c#'s typesysteem is. :)

Vitamine D tekorten in Nederland | Corona: wat niet gepost kan worden


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

NetForce1 schreef op donderdag 11 februari 2010 @ 12:31:
[...]

Nee, dat kan gewoon zijn:
Java:
1
List<String> list = Lists.newArrayList();

dat kan de compiler voor je uitvogelen
De compiler vogelt niets uit. Het punt is dat generics alleen op compilerniveau leven, en List<String> eigenlijk gewoon een List is met wat extra compile-time bescherming en casting. Het is niet voor niets dat het een warning oplevert. Dit "mag" ook:
Java:
1
2
3
ArrayList<String> a = new ArrayList<String>();
ArrayList b = a;
ArrayList<Double> c = b;

De compiler doet hier net zoveel als in jouw voorbeeld, en het is net zo (on)veilig. Onder water zijn zowel a, b als c gewoon een ArrayList.

[Voor 3% gewijzigd door .oisyn op 11-02-2010 13:11]

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • Tedkees
  • Registratie: juni 2005
  • Laatst online: 18-06-2015
Ik denk dat het gebruik van var min of meer samenhangt met hoe je ontwerp is. Wat betreft primaire types (int, bool, string, eigenlijk alles met een mooie alias in C#) gebruik ik doorgaans de expliciete manier:

C#:
1
2
3
4
5
public void SomeMethod()
{
   int numberOfTries = 0;
   bool isConnected = true;
}


In loops juist weer vaak var:

C#:
1
2
3
4
for(var i = 0; i < someArray.Lengh; i++)
{
  // do iets
}


For loops zijn wat mij betreft 9 van de 10 keer toch int, dan hoef ik het niet te weten. Dit heeft niets te maken met het aantal letters (int is net zo lang), maar met de nutteloze informatie die je verbergt. Ik hoef niet te weten dat 't een Int32 is in dit geval.

Wat betreft returnvalues van methods gebruik ik toch graag var. Waarom? Omdat je door het gebruik van var gedwongen wordt om goede namen te geven aan je methods, en de variabelen waar je de return values in stopt. Meestal gaat dat ook by convention. Als ik een method heb die een entity naam in meervoud heeft, dan geeft 't per definitie een IEnumerable<T> terug. Zou best een List<T> kunnen zijn, of een T[], of een IQueryable<T>:

C#:
1
2
var relatedProducts = someProduct.getRelatedProducts();
// relatedProducts is dus op z'n minst IEnumerable<T>


Als laatste punt natuurlijk anonieme types, maar daar kom je simpelweg niet omheen.


Uiteindelijk komt het volgens mij vooral neer op de informatie die je WIL zien expliciet uitschrijven, en de informatie die je niet hoeft te zien te verbergen. Wat betreft return types van functies en dergelijke is het vaak helemaal niet boeiend wat voor type er terug komt. Wat interessant is, is wat het gedrag ervan is.

Wanneer gebruik ik het NIET? Als ik een type heb dat een (aantal) interface(s) implementeert. Het komt regelmatig voor dat ik puur op die ene interface wil vertrouwen, dan zal ik dus ook expliciet proberen die interface te definieren in de code.

  • o0oPhreako0o
  • Registratie: augustus 2008
  • Laatst online: 17-03-2018
evidoth schreef op donderdag 11 februari 2010 @ 12:46:
[...]


Deze mag dan ook niet, var mag enkel voorkomen als lokale variabele declaratie, maar met het dynamic keyword in C# 4.0 gaat dit wel.
Je hebt helemaal gelijk, had het er zo 'neergeklapt'... stomme fout :)
bedankt

#phreak


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

.oisyn schreef op donderdag 11 februari 2010 @ 13:11:
[...]

De compiler vogelt niets uit.
Jawel, de Java compiler doet (een beetje) aan type inference voor generic static methods. Dit is nodig voor de type checking. Dit geeft bijv. een type error:

Java:
1
List<String> list = Lists.newArrayList(3);

De reden is dat de compiler het volgende heeft uitgevogeld:
Java:
1
List<String> list = Lists.<Integer>newArrayList(3);  // na type inference

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

RobIII schreef op donderdag 11 februari 2010 @ 11:37:
[...]

Dus een Dictionary<T, List<T>> :? :Y) :P
Of zelfs Dictionary<T, Dictionary<T, T>> :P
Een dictionary is geen map. Een map is namelijk georderd, een dictionary niet. Een map kan dus range queries afhandelen, en daaruit blijkt meteen ook waarom een map<K,list<V>> onhandig is - je kunt niet makkelijk over een range van elementen itereren, wat met een multimap wel kan.

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

RayNbow schreef op donderdag 11 februari 2010 @ 13:18:
[...]

Jawel, de Java compiler doet (een beetje) aan type inference voor generic static methods. Dit is nodig voor de type checking. Dit geeft bijv. een type error:

Java:
1
List<String> list = Lists.newArrayList(3);
Dat geeft een error ja, maar mijn voorbeeld gaf gewoon een simpele unchecked warning. Bovendien ging het om het voorbeeld zonder parameters, maar blijkbaar mag dat idd. De opmerking van evidoth dat je een unchecked warning krijgt klopte dus niet.

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • Woy
  • Registratie: april 2000
  • Niet online

Woy

Moderator Devschuur®
RayNbow schreef op donderdag 11 februari 2010 @ 13:18:
[...]

Jawel, de Java compiler doet (een beetje) aan type inference voor generic static methods. Dit is nodig voor de type checking. Dit geeft bijv. een type error:

Java:
1
List<String> list = Lists.newArrayList(3);

De reden is dat de compiler het volgende heeft uitgevogeld:
Java:
1
List<String> list = Lists.<Integer>newArrayList(3);  // na type inference
Maar de type inference gebeurt aan de hand van de parameters. Er word geen type inference gedaan aan de hand van de variabele waar hij later aan geassigned word. Het voorbeeld, zonder parameters, zal dus volgens mij ook nooit een List<String> op kunnen leveren. Nou kan dat hier wel goed gaan omdat Generics in java Compiletime werken, maar in C# zou dat nooit kunnen, en zou je dus verplicht de type parameter mee moeten geven als hij het niet aan de hand van de parameters af kan leiden.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

.oisyn schreef op donderdag 11 februari 2010 @ 13:23:
[...]

Dat geeft een error ja, maar mijn voorbeeld gaf gewoon een simpele unchecked warning. Bovendien ging het om het voorbeeld zonder parameters, maar blijkbaar mag dat idd. De opmerking van evidoth dat je een unchecked warning krijgt klopte dus niet.
Maar ook bij de Lists.newArrayList zonder parameters doet de compiler aan type inference. Het afgeleide type kun je in Eclipse zien door je muis erboven te laten hangen. (Het is dus waar dat je geen unchecked warnings krijgt)

In jouw voorbeeld met de ArrayList maak je btw gebruik van de ArrayList constructor en niet een static method. De Java compiler doet alleen aan type inference bij static methods. De type-regels in Java zijn zo dat C<T> een subtype van C (raw) is, dat je C als C<T> kunt gebruiken (met unchecked warning) en dat het gebruik van C.covariantGenericMethod(args) ook warnings oplevert.
pedorus schreef op donderdag 11 februari 2010 @ 12:53:
Zo zie je maar weer hoe krachtig c#'s typesysteem is. :)
Offtopic, maar zo krachtig vind ik 't niet. ;) Het volgende kan ik niet uitdrukken in C#:
C#:
1
2
3
4
5
static ?<int> addOne<?>(?<int> xs)
{
    return from x in xs
           select x + 1;
}

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • Snake
  • Registratie: juli 2005
  • Laatst online: 23:29

Snake

Los Angeles, CA, USA

RayNbow schreef op donderdag 11 februari 2010 @ 14:00:
[...]

[...]

Offtopic, maar zo krachtig vind ik 't niet. ;) Het volgende kan ik niet uitdrukken in C#:
C#:
1
2
3
4
5
static ?<int> addOne<?>(?<int> xs)
{
    return from x in xs
           select x + 1;
}
Waarom zou je dat uberhaupt doen? Zet dan ipv dat ? IEnumerable<int> ofzo :)

+ als dat zou compileren, hoe zou de compiler dan moeten kunnen afleiden of select er uberhaupt op werkt?

[Voor 46% gewijzigd door Snake op 11-02-2010 14:04]

Going for adventure, lots of sun and a convertible! | GMT-8


  • mark platvoet
  • Registratie: februari 2002
  • Laatst online: 19-08-2010

mark platvoet

Moutarde apres le diner

RayNbow schreef op donderdag 11 februari 2010 @ 13:18:
Jawel, de Java compiler doet (een beetje) aan type inference voor generic static methods. Dit is nodig voor de type checking. Dit geeft bijv. een type error:
Java:
1
List<String> list = Lists.newArrayList(3);

De reden is dat de compiler het volgende heeft uitgevogeld:
Java:
1
List<String> list = Lists.<Integer>newArrayList(3);  // na type inference
Ik denk dat ik de strekking van het voorafgaande betoog mis maar het volgende compileert prima, zonder warnings, in Java.
Java:
1
2
3
4
5
List<String> strings = newArrayList();//compileert zonder warnings
    
    public static<E> List<E> newArrayList() {
        return new ArrayList<E>();
    }


In C# werkt dat truukje helaas niet en moet je het type expliciet definieren:
C#:
1
2
3
4
5
6
        IList<string> strings = NewList(); //compileert niet
        IList<string> strings2 = NewList<string>(); //compileert wel

        public static IList<T> NewList<T>() {
            return new List<T>();
        }

Religion has no place in public schools the way facts have no place in organized religion


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

RayNbow schreef op donderdag 11 februari 2010 @ 14:00:
[...]

Maar ook bij de Lists.newArrayList zonder parameters doet de compiler aan type inference
Ik zei toch al dat het evidoth's opmerking was die mij op het verkeerde been zette? :) Hij had het erover dat je een unchecked warning kreeg. Als dat het geval was dan deed de compiler geen type inference. Maar je krijgt de warning niet, wat impliceert dat hij dat idd wel doet.
RayNbow schreef op donderdag 11 februari 2010 @ 14:00:
C#:
1
2
3
4
5
static ?<int> addOne<?>(?<int> xs)
{
    return from x in xs
           select x + 1;
}
Vind je het gek dat dat niet kan, ik snap niet eens wat je nou eigenlijk probeert te doen, hoe moet een compiler dat dan snappen ;)

[Voor 51% gewijzigd door .oisyn op 11-02-2010 14:35]

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

Snake schreef op donderdag 11 februari 2010 @ 14:01:
[...]

Waarom zou je dat uberhaupt doen? Zet dan ipv dat ? IEnumerable<int> ofzo :)

+ als dat zou compileren, hoe zou de compiler dan moeten kunnen afleiden of select er uberhaupt op werkt?
Dan werkt addOne alleen op IEnumerable<int>s. Ik wil dat addOne voor elke C<int> werkt, waarbij C de Select() LINQ operator ondersteunt. C#'s type system is niet krachtig genoeg om de LINQ operators in een of meerdere interfaces op te vangen (wegens gebrek aan higher-kinded polymorphism).
mark platvoet schreef op donderdag 11 februari 2010 @ 14:09:
[...]

Ik denk dat ik de strekking van het voorafgaande betoog mis maar het volgende compileert prima, zonder warnings, in Java.
Java:
1
2
3
4
5
List<String> strings = newArrayList();//compileert zonder warnings
    
    public static<E> List<E> newArrayList() {
        return new ArrayList<E>();
    }
Ik beweer nergens dat dat warnings oplevert? :p
.oisyn schreef op donderdag 11 februari 2010 @ 14:32:
Ik zei toch al dat het evidoth's opmerking was die mij op het verkeerde been zette? :)
Daar kwam ik ook achter tijdens het typen van m'n vorige reactie. Vandaar dat stuk tussen haakjes in de eerste alinea. :p


* RayNbow slaat .oisyn. Niet stiekem dingen erbij tikken! :p
.oisyn schreef op donderdag 11 februari 2010 @ 14:32:
Vind je het gek dat dat niet kan, ik snap niet eens wat je nou eigenlijk probeert te doen, hoe moet een compiler dat dan snappen ;)
Op het vraagteken kun je zoals hierboven opgemerkt IEnumerable invullen. Maar je zou ook een andere interface/class-naam invullen, zolang het maar Select(Func<A,B>) ondersteunt. C# dwingt me nu eig. om dit te typen:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static IEnumerable<int> addOne(IEnumerable<int> xs) 
{ 
    return from x in xs 
           select x + 1; 
}
static IObservable<int> addOne(IObservable<int> xs)   // (IObservable uit Rx)
{ 
    return from x in xs 
           select x + 1; 
}

static Foo<int> addOne(Foo<int> xs) 
{ 
    return from x in xs 
           select x + 1; 
}
static Bar<int> addOne(Bar<int> xs) 
{ 
    return from x in xs 
           select x + 1; 
}
// enzovoorts... voor elke class/interface die de LINQ Select operator bevat...

[Voor 27% gewijzigd door RayNbow op 11-02-2010 14:48]

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • Snake
  • Registratie: juli 2005
  • Laatst online: 23:29

Snake

Los Angeles, CA, USA

Er moet toch ergens een relatie tussen die types zijn? En die zijn er momenteel niet. Dus dan kan je toch niets omgekeerd 'generic' maken?

Going for adventure, lots of sun and a convertible! | GMT-8


  • Woy
  • Registratie: april 2000
  • Niet online

Woy

Moderator Devschuur®
RayNbow schreef op donderdag 11 februari 2010 @ 14:38:
[...]
Op het vraagteken kun je zoals hierboven opgemerkt IEnumerable invullen. Maar je zou ook een andere interface/class-naam invullen, zolang het maar Select(Func<A,B>) ondersteunt. C# dwingt me nu eig. om dit te typen:
Dat komt meer doordat Select een extension method is, en er is geen manier om een constraint te leggen op welke extension methods er minstens moeten zijn. Als Select in een interface of base-type had gezeten dan was het geen probleem geweest.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

Woy schreef op donderdag 11 februari 2010 @ 15:23:
[...]

Dat komt meer doordat Select een extension method is, en er is geen manier om een constraint te leggen op welke extension methods er minstens moeten zijn. Als Select in een interface of base-type had gezeten dan was het geen probleem geweest.
Het gebrek aan higher-kinded polymorphism zorgt ervoor dat je de LINQ query operators niet in een interface kan stoppen.

Higher-kinded C# zou er ongeveer zo uit kunnen zien:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Higher-kinded C#
interface IFunctor<F>
{
    F<B> Select(this F<A>, Func<A,B>);
}

interface IMonad<M> : IFunctor<M>
{
    M<B> SelectMany(this M<A>, Func<A, M<B>>);
}

static F<int> addOne<F>(F<int> xs) where F : IFunctor<F>
{  
    return from x in xs  
           select x + 1;  
}

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • Grijze Vos
  • Registratie: december 2002
  • Laatst online: 18-09 23:10
Tja, C# is nou eenmaal geen functionele taal. Misschien moet je gewoon F# gaan gebruiken?

Overigens, normaal gesproken hoor je gewoon IEnumerable te implementeren als je Linq ondersteunt, dus dan zou dat geen issue moeten zijn.

[Voor 44% gewijzigd door Grijze Vos op 11-02-2010 18:20]

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

Grijze Vos schreef op donderdag 11 februari 2010 @ 18:19:
Tja, C# is nou eenmaal geen functionele taal. Misschien moet je gewoon F# gaan gebruiken?
Het doel van higher-kinded polymorphism is hetzelfde van polymorfisme: abstractie. Het ook kunnen abstraheren over typeconstructors ipv alleen types is niet iets dat alleen voor functionele talen is weggelegd.
Overigens, normaal gesproken hoor je gewoon IEnumerable te implementeren als je Linq ondersteunt, dus dan zou dat geen issue moeten zijn.
Dit is juist een grote misvatting. Het ondersteunen van LINQ staat niet gelijk aan het implementeren van IEnumerable. IEnumerable types zijn, zoals de naam van de interface al zegt, enumereerbaar. Je hoeft niet enumereerbaar te zijn om LINQ te kunnen implementeren. Een voorbeeld is een functie. Kan je elke functie enumereren?

De Select operator voor functies:
C#:
1
2
3
4
public static Func<E, B> Select<E, A, B>(this Func<E, A> f, Func<A, B> g)
{
    return x => g(f(x));
}

Voorbeeldje:
C#:
1
2
3
var res = (from x in (Func<int,int>)(x => x+1)
           select -x)(3);
Console.WriteLine(res); // schrijft netjes -4 naar het scherm


En wat dacht je van IObservable? IObservable is de duale van IEnumerable (zit in Reactive Extensions for .NET (Rx)) en implementeert ook de LINQ operators.

Edit: wat Rx sample code, gebaseerd op deze ietwat outdated video tutorial.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// drag/drop van een image in een canvas:
var mouseDown = from evt in Observable.FromEvent<MouseButtonEventArgs>(this, "MouseDown")
                select evt.EventArgs.GetPosition(this);

var mouseUp = from evt in Observable.FromEvent<MouseButtonEventArgs>(this, "MouseUp")
              select evt.EventArgs.GetPosition(this);

var mouseMove = from evt in Observable.FromEvent<MouseEventArgs>(this, "MouseMove")
                select evt.EventArgs.GetPosition(this);

var q = from start in mouseDown
        from delta in mouseMove.StartWith(start).TakeUntil(mouseUp)
                        .Let(mm => mm.Zip(mm.Skip(1), (prev, cur) =>
                            new { X = cur.X - prev.X, Y = cur.Y - prev.Y }))
        select delta;

q.ObserveOn(SynchronizationContext.Current).Subscribe(value =>
{
    Canvas.SetLeft(image, Canvas.GetLeft(image) + value.X);
    Canvas.SetTop(image, Canvas.GetTop(image) + value.Y);
});

[Voor 27% gewijzigd door RayNbow op 11-02-2010 22:43]

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • pedorus
  • Registratie: januari 2008
  • Niet online
Je legt nu prima uit dat select eigenlijk gewoon de functie 'Select' aanroept. Het probleem is dan ook met jouw voorstel je niet eens een ?<int> hoeft te hebben om een select op die ints te doen. Dus iets als:
C#:
1
2
3
4
5
6
7
8
    class TestSelect
    {
        public IEnumerable<TResult> Select<TResult>(Func<int, TResult> selector)
        {
            for (int i = 0; i < 100; i++)
                yield return selector(100); 
        } 
    }

Hoe zou jouw AddOne hier moeten gaan werken? Dan zou je al moeten binden aan classes die een functie Select hebben die een Func<int, TResult> accepteert. Lijkt me niet een common use case met veel praktisch nut, en ook niet iets dat makkelijk te fixen is. :)
.oisyn schreef op donderdag 11 februari 2010 @ 13:19:
[...]

Een dictionary is geen map. Een map is namelijk georderd, een dictionary niet. Een map kan dus range queries afhandelen, en daaruit blijkt meteen ook waarom een map<K,list<V>> onhandig is - je kunt niet makkelijk over een range van elementen itereren, wat met een multimap wel kan.
Ik denk dat het iets uit de c-wereld is om zo te denken. ;) In java, of hier in Google's implementatie, is een ArrayListMultimap intern zeer vergelijkbaar met een Dictionary<TKey,List<TValue>>. En als er iets anders werd bedoelt heb ik gelukkig var gebruikt, dat spaart weer werk bij veranderen. :p


Terug over var. Ik vond dit eigenlijk wel een mooi voorbeeld:
Kayshin schreef op woensdag 27 januari 2010 @ 13:17:
C#:
1
2
3
4
5
6
7
8
9
10
Uri baseNetTcpAddress = new Uri("net.tcp://localhost:9000");
ServiceHost host = new ServiceHost(typeof(PingService), new Uri[] { baseNetTcpAddress });
ServiceMetadataBehavior metadataBehavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(metadataBehavior);
System.ServiceModel.Channels.Binding mexTcpBinding =
System.ServiceModel.Description.MetadataExchangeBindings.CreateMexTcpBinding();

host.AddServiceEndpoint(typeof(IMetadataExchange), mexTcpBinding, "mex");
host.AddServiceEndpoint(typeof(IOrderPizza), new NetTcpBinding(SecurityMode.None, true), string.Empty);
host.Open();
Zonder de volgorde te veranderen, en door enkel te snijden in typeaanduidingen, wordt het wat mij betreft al een stuk duidelijker:
C#:
1
2
3
4
5
6
7
8
9
10
            var baseNetTcpAddress = new Uri("net.tcp://localhost:9000");
            var host = new ServiceHost(typeof(PingService), baseNetTcpAddress);
            var metadataBehavior = new ServiceMetadataBehavior();
            host.Description.Behaviors.Add(metadataBehavior);
            var mexTcpBinding = MetadataExchangeBindings.CreateMexTcpBinding();

            host.AddServiceEndpoint(typeof(IMetadataExchange), mexTcpBinding, "mex");
            host.AddServiceEndpoint(typeof(IOrderPizza),
                new NetTcpBinding(SecurityMode.None, true), "");
            host.Open();

Vitamine D tekorten in Nederland | Corona: wat niet gepost kan worden


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

pedorus schreef op donderdag 11 februari 2010 @ 22:55:
Ik denk dat het iets uit de c-wereld is om zo te denken. ;) In java, of hier in Google's implementatie, is een ArrayListMultimap intern zeer vergelijkbaar met een Dictionary<TKey,List<TValue>>. En als er iets anders werd bedoelt heb ik gelukkig var gebruikt, dat spaart weer werk bij veranderen. :p
Nee, dat heeft geen zak met C te maken :). Geordende containers zijn essentieel voor bepaalde algoritmen. Als ik een map<int, string> heb, dan kan ik in O(log n + k) alle strings enumereren binnen een bepaald range van integers. Dat kan met een dictionary/hashmap niet, omdat die ongeordend zijn. Dat is dus het ene verschil.

Het andere verschil is het multi gedeelte; je zou een multimap<int, string> kunnen definieren als een map<int, list<string>>. Het enumereren over elementen wordt dan ingewikkelder, omdat ik niet alleen over de elementen van de multimap heen moet lopen, maar ook nog eens over de elementen van de list. Daar is dan een geneste loop voor nodig, tenzij je een iterator/enumerator schrijft die die poespas voor je afhandelt. Maar het is hoe dan ook meer werk en meer complexiteit. Een multimap is in dat opzicht gewoon praktischer.

Het verschil met de dictionary is dat het dan niet zo boeit, omdat je toch niet zo snel over meerdere elementen in de dictionary zou lopen, maar louter over de meerdere elementen met dezelfde key. Voor die usecase is een dictionary<int, list<string>> prima geschikt, en geen reden om een multimap<int, string> te gebruiken.

[Voor 3% gewijzigd door .oisyn op 12-02-2010 00:14]

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

pedorus schreef op donderdag 11 februari 2010 @ 22:55:
Je legt nu prima uit dat select eigenlijk gewoon de functie 'Select' aanroept.
In dit simpele geval, ja. In iets uitgebreidere queries zoals met meerdere from-clauses wordt de query syntax vertaald naar SelectMany-aanroepen.
Het probleem is dan ook met jouw voorstel je niet eens een ?<int> hoeft te hebben om een select op die ints te doen.
:?

Wat is dat voor redenatie? Als ik nu een IEnumerable<int> heb, maar ook een IObservable<int>, dan moet ik dus maar mijn addOne functie twee keer schrijven? Of stel je voor dat ik op een of andere manier die IObservable met een hamer bewerk totdat het in de vorm van IEnumerable past?
Dus iets als:
C#:
1
2
3
4
5
6
7
8
    class TestSelect
    {
        public IEnumerable<TResult> Select<TResult>(Func<int, TResult> selector)
        {
            for (int i = 0; i < 100; i++)
                yield return selector(100); 
        } 
    }

Hoe zou jouw AddOne hier moeten gaan werken? Dan zou je al moeten binden aan classes die een functie Select hebben die een Func<int, TResult> accepteert.
Ik volg je niet. Het gaat er niet om dat ik een Func<int,B> wil toepassen op ints, zoals je hierboven doet. Het gaat erom dat ik een functie wil kunnen toepassen op alle mogelijke functors, niet alleen op een select gezelschap onder de noemer IEnumerable<int>.
Lijkt me niet een common use case met veel praktisch nut,
Mijn addOne is niets anders dan een simpel, kunstmatig voorbeeld om aan te tonen dat zonder higher-kinded polymorphism ik meerdere keren een functie moet schrijven, waarbij de body exact hetzelfde is en alleen de type signature verschilt.

Momenteel is het praktische nut nog niet heel erg groot, maar dat komt omdat er nog weinig andere classes zijn die de LINQ operators implementeert. Standaard heb je alleen alle IEnumerable en IQueryable classes en sinds kort kun je spelen met Rx's IObservable classes. Nu kun je er nog mee wegkomen om 1 extra kopie te maken met alleen een andere type signature...

...maar wanneer je zo'n extra kopie maakt, heb je je dan in feite jezelf niet herhaald? Is dat misschien niet net zo erg als de herhaling in "List<string> stringList = new List<string>();"? :)
en ook niet iets dat makkelijk te fixen is. :)
Het is ook lastig te fixen, maar dat verandert weinig aan m'n mening dat C#'s type system niet erg krachtig is. ;)
.oisyn schreef op vrijdag 12 februari 2010 @ 00:12:
Nee, dat heeft geen zak met C te maken :). Geordende containers zijn essentieel voor bepaalde algoritmen. Als ik een map<int, string> heb, dan kan ik in O(log n + k) alle strings enumereren binnen een bepaald range van integers. Dat kan met een dictionary/hashmap niet, omdat die ongeordend zijn. Dat is dus het ene verschil.
Misschien wel met het jargon dat C of C++ proggers gebruiken, waarin map dus blijkbaar refereert naar een datastructuur met de eigenschap dat de keys geordend zijn. Voor mij is een map conceptueel niets anders dan een afbeelding van keys naar values.

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • Neverwinterx
  • Registratie: december 2005
  • Laatst online: 21:32
Ik vind het wat vreemd dat dit wordt aangehaald als een goed gebruik van var:
Java:
1
2
List<String> bad = new ArrayList<String>();
var good = new ArrayList<String>();


Een goed systeem (zoals in Java 7 zal komen) zou dit moeten kunnen doen:
Java:
1
List<String> best = new ArrayList<>();

Een wat uitgebreider voorbeeld:
Java:
1
Map<String, List<String>> anagrams = new HashMap<>();

Dat vermijdt ook de verbositeit, maar sleurt er niet iets obscuur als var bij.
(http://mail.openjdk.java....2009-February/000009.html)

  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

Dat vermijdt de verbositeit in Java alleen bij het instantiëren.

[Voor 13% gewijzigd door RayNbow op 12-02-2010 00:36]

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • Wolfboy
  • Registratie: januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Grijze Vos schreef op woensdag 10 februari 2010 @ 13:01:
[...]

Ik vind loopjes juist bij uitstek de plek om dit te doen.

C#:
1
2
3
4
List<NewsArticle> articles = News.GetArticles();
foreach(var article in articles)
{ // doe iets
}

Hartstikke leesbaar.
Hier declareer ik wel het type van de lijst, omdat die uit een externe functie komt.
Prima leesbaar inderdaad, maar waarom expliciet een List aanmaken?

Dan vind ik deze optie beter:
C#:
1
2
3
4
var articles = News.GetArticles();
foreach(NewsArticle article in articles)
{ // doe iets
}


Of als je articles toch niet meer nodig hebt misschien zelfs dit:
C#:
1
2
3
foreach(NewsArticle article in News.GetArticles())
{ // doe iets
}

Blog [Stackoverflow] [LinkedIn]


  • Grijze Vos
  • Registratie: december 2002
  • Laatst online: 18-09 23:10
Bedoel je computationele complexiteit? Want dat lijkt me nog steeds O(log n + k), waarbij k het aantal elementen is waarover je itereert. Nou ja, het is eigenlijk O(log n m*p), waarbij m*p=k.
RayNbow schreef op vrijdag 12 februari 2010 @ 00:26:
[...]

Momenteel is het praktische nut nog niet heel erg groot, maar dat komt omdat er nog weinig andere classes zijn die de LINQ operators implementeert. Standaard heb je alleen alle IEnumerable en IQueryable classes en sinds kort kun je spelen met Rx's IObservable classes. Nu kun je er nog mee wegkomen om 1 extra kopie te maken met alleen een andere type signature...
En het praktisch nut wordt ook niet groter. Als je zelf een Linq provider wilt schrijven is het de bedoeling dat je IQueryable implementeert (ik zei IEnumerable in mijn vorige post, maar ik bedoelde IQueryable.) Ik vind het perfect acceptabel dat die eis er is. Leuk dat je nu de wiskundige duaal hebt in de vorm van IObservable, maar welke interfaces verwacht je nog meer te implementeren die niet een van die twee kunnen implementeren?
Het is ook lastig te fixen, maar dat verandert weinig aan m'n mening dat C#'s type system niet erg krachtig is. ;)
Ik was niet degene die die opmerking maakte over de kracht van C#'s type systeem, maar ik denk dat die poster bedoelde in vergelijking met andere imperatieve talen, niet in vergelijking met functionele talen. Je commentaar komt op mij over als functioneel fanboy-talk, om eerlijk te zijn.

[Voor 67% gewijzigd door Grijze Vos op 12-02-2010 09:31]

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

RayNbow schreef op vrijdag 12 februari 2010 @ 00:26:
Misschien wel met het jargon dat C of C++ proggers gebruiken, waarin map dus blijkbaar refereert naar een datastructuur met de eigenschap dat de keys geordend zijn. Voor mij is een map conceptueel niets anders dan een afbeelding van keys naar values.
Hmmm idd, daar heb ik helemaal niet bij stilgestaan :)
Grijze Vos schreef op vrijdag 12 februari 2010 @ 09:20:
[...]

Bedoel je computationele complexiteit?
Nee, ik bedoel meer code complexiteit. Een dubbele loop.

[Voor 49% gewijzigd door .oisyn op 12-02-2010 11:09]

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

Grijze Vos schreef op vrijdag 12 februari 2010 @ 09:20:
[...]

En het praktisch nut wordt ook niet groter. Als je zelf een Linq provider wilt schrijven is het de bedoeling dat je IQueryable implementeert (ik zei IEnumerable in mijn vorige post, maar ik bedoelde IQueryable.) Ik vind het perfect acceptabel dat die eis er is.
Die eis is er niet.
Leuk dat je nu de wiskundige duaal hebt in de vorm van IObservable, maar welke interfaces verwacht je nog meer te implementeren die niet een van die twee kunnen implementeren?
Kan jij Func<E,A> de IEnumerable<A> of IObservable<A> interface laten implementeren dan? Ik heb hier laten zien dat het de Select operator kan implementeren. SelectMany is trouwens ook geen probleem:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static Func<E,B> SelectMany<E, A, B>(this Func<E, A> f, Func<A, Func<E, B>> g) 
{
    return e => g(f(e))(e);
}
public static Func<E, C> SelectMany<E, A, B, C>(
    this Func<E, A> f,
    Func<A, Func<E, B>> g,
    Func<A, B, C> h
)
{
    return e => h(f(e), f.Select(g)(e)(e));
}

// gebruik:
var res = (from x in (Func<int,int>)(e => e+1)
           from y in (Func<int, int>)(e => e+1)
           select x+y)(3); // levert [s]7[/]8 op (edit: typfout)


Dit is trouwens een voorbeeld waarbij de compiler de implementatie van de SelectMany's zelf zou moeten kunnen vinden. Immers, zowel (e -> a) -> (a -> (e -> b)) -> (e -> b) als (e -> a) -> (a -> (e -> b)) -> (a -> b -> c) -> (e -> c) zijn te bewijzen in de propositielogica.
[...]

Ik was niet degene die die opmerking maakte over de kracht van C#'s type systeem, maar ik denk dat die poster bedoelde in vergelijking met andere imperatieve talen, niet in vergelijking met functionele talen.
Extension methods laten alleen niet de kracht van een type system zien. Het laat eerder zien dat je wat syntactische suiker kunt toevoegen als je de regels uitbreidt waar je een methode kunt vinden.
Je commentaar komt op mij over als functioneel fanboy-talk, om eerlijk te zijn.
Is het verkeerd om abstractie hoog in het vaandel te hebben? :p Daarnaast, wat maakt higher-kinded generics "functioneel"?

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • Deathraven
  • Registratie: november 2001
  • Laatst online: 21-09 21:26
RayNbow schreef op vrijdag 12 februari 2010 @ 13:10:

[...]

Is het verkeerd om abstractie hoog in het vaandel te hebben? :p Daarnaast, wat maakt higher-kinded generics "functioneel"?
Strict gezien blijft het een uitbreiding op het (OO gebaseerde) type systeem. Maar als je gaat kijken naar de mogelijkheden die deze "uitbreiding" je zal geven zullen veel mensen dit al snel als een feature in een functionele taal bestempelen. Puur omdat je niet gewend bent dit soort constructies te zien in .Net.

Komt op neer dat higher-kinded-generics je in staat stelt om meer "functioneel achtige" dingen te doen in een OO taal. Wellicht dat mensen het daarom als "functioneel" bestempelen.

[Voor 13% gewijzigd door Deathraven op 12-02-2010 14:25. Reden: verduidelijking]


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

Er is niets functioneel aan. Het is generic programming. In C++ kan het overigens wel (behalve de select syntax natuurlijk). Wel weer jammer is overigens dat je in C++0x geen template parameters kunt deduceren aan de hand van een lambda, wat ik een beetje een gemiste kans vindt :/

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • Alex)
  • Registratie: juni 2003
  • Laatst online: 21-09 13:58
Ik gebruik var nooit. Als ik var tegenkom in de code van anderen, klik ik erop en laat ik ReSharper het type expliciet specificeren. Ik vind var's niet fijn werken, en met het oog op consistente code gebruik ik ook een expliciet type bij bijvoorbeeld Collections. Dan maar iets meer letters, IntelliSense (zeker de R#-versie) scheelt toch een hoop typwerk.

Zelfs het resultaat van LINQ-queries gooi ik in een strongly-typed variabele:

C#:
1
2
3
IEnumerable<Reservering> reserveringen = from Reservering r in GetReserveringen()
                                         where r.Id.ToString().StartsWith("42")
                                         select r;


Prachtig O+

We are shaping the future


  • pedorus
  • Registratie: januari 2008
  • Niet online
RayNbow schreef op vrijdag 12 februari 2010 @ 00:26:
Wat is dat voor redenatie? Als ik nu een IEnumerable<int> heb, maar ook een IObservable<int>, dan moet ik dus maar mijn addOne functie twee keer schrijven?
Nee, liefst niet als het logisch is om dezelfde functie op beide toe te passen. Ik ben zelf ook sterk voorstander om zo generiek mogelijke methodes te hebben. Als voorbeeld: in pedorus in "\[C#][discussie] Lekker veel var gebruiken?" staat een methode die alleen voor Lists werkt, maar generieker had gemoeten:
C#:
1
2
3
4
5
6
7
8
        public static void Put<TCol, TKey, TValue>(this IDictionary<TKey, TCol> d,
                TKey key, TValue value) 
            where TCol : ICollection<TValue>, new()
        {
            TCol elem;
            if (d.TryGetValue(key, out elem)) elem.Add(value);
            else d[key] = new TCol() { value };
        }

Dan hoef je voor een SortedList<TKey,HashSet<TValue>> niet opeens een andere functie te hebben.
Of stel je voor dat ik op een of andere manier die IObservable met een hamer bewerk totdat het in de vorm van IEnumerable past?
Ik vraag me af of er echt concrete voorbeelden zijn van functies die nuttig zijn op die beide types. Als dat zo is, hadden ze het liefst beiden eenzelfde interface gehad, waarbij ik ook nog links zie richting AOP om zoiets achteraf toe te voegen. AOP wordt nog niet in c# ondersteund vanwege potentiële havoc en nog niet duidelijk genoeg praktisch nut. Over deze ondersteuning:
Bill Venners: So the type must either extend a class or implement interfaces.

Anders Hejlsberg: Yes. And we could have gone further. We did give thought to going further, but it gets very complicated. And it's not clear that the added complexity is worth the small yield that you get. If something you want to do is not directly supported in the constraint system, you can do it with a factory pattern. You could have a Matrix<T>, for example, and in that Matrix you would like to define a dot product method. That of course that means you ultimately need to understand how to multiply two Ts, but you can't say that as a constraint, at least not if T is int, double, or float. But what you could do is have your Matrix take as an argument a Calculator<T>, and in Calculator<T>, have a method called multiply. You go implement that and you pass it to the Matrix.
Ik volg je niet. Het gaat er niet om dat ik een Func<int,B> wil toepassen op ints, zoals je hierboven doet. Het gaat erom dat ik een functie wil kunnen toepassen op alle mogelijke functors, niet alleen op een select gezelschap onder de noemer IEnumerable<int>.
Het gaat erom dat jouw 2-regelige operatie op die class werkt, hoewel die class geen ?<int> is. Je hebt dan dus weer een nieuwe, losse implementatie nodig:
C#:
1
2
3
4
5
        public static IEnumerable<int> addOne(this TestSelect xs)
        {
            return from x in xs
                   select x + 1;
        }

Dit lijkt me niet iets dat het type-systeem van c# moet oplossen, maar meer een geval dat de class TestSelect bepaalde interfaces gewoon had moeten implementeren.
Mijn addOne is niets anders dan een simpel, kunstmatig voorbeeld om aan te tonen dat zonder higher-kinded polymorphism ik meerdere keren een functie moet schrijven, waarbij de body exact hetzelfde is en alleen de type signature verschilt.
[...]
...maar wanneer je zo'n extra kopie maakt, heb je je dan in feite jezelf niet herhaald? Is dat misschien niet net zo erg als de herhaling in "List<string> stringList = new List<string>();"? :)
Ik zit me af te vragen of een functie niet vaak ook hele andere functionaliteit krijgt heeft als twee classes niet dezelfde interface hebben. Als de naam dan niet meer klopt, dan is herhaling beter. Daarnaast zit je natuurlijk met afnemende meeropbrengsten. Het geval "List<string> stringList = new List<string>();" komt veel vaker voor, en -in mijn ogen- is daar nu een oplossing voor: var. :p
RayNbow schreef op vrijdag 12 februari 2010 @ 13:10:
C#:
17
           select x+y)(3); // levert 7 op
Het lijkt mij 8 (2*3+2), maar sowieso is het zonder concrete toepassingen mij niet helemaal duidelijk waarom je hier c# en linq voor wil gebruiken, en al helemaal niet waarom je een operatie op functies ook op IEnumerables wil toepassen. ;)
Neverwinterx schreef op vrijdag 12 februari 2010 @ 00:28:
Ik vind het wat vreemd dat dit wordt aangehaald als een goed gebruik van var:
Java:
1
2
List<String> bad = new ArrayList<String>();
var good = new ArrayList<String>();


Een goed systeem (zoals in Java 7 zal komen) zou dit moeten kunnen doen:
Java:
1
List<String> best = new ArrayList<>();

Een wat uitgebreider voorbeeld:
Java:
1
Map<String, List<String>> anagrams = new HashMap<>();

Dat vermijdt ook de verbositeit, maar sleurt er niet iets obscuur als var bij.
(http://mail.openjdk.java....2009-February/000009.html)
Ik heb ook even naar deze link gekeken. Persoonlijk zie ik niet helemaal in wat er 'obscuur' is aan var. Daarnaast herhaal je nu List volgens interface=implementatie. Ik zie nog steeds niet in wat het grote voordeel daarvan is bij lokale variabelen. En ik vraag me af of het echt logisch is om aan de right-hand-side opeens informatie te hebben die niet op zichzelf staat. De '='-operator werkt zo 2 kanten op. Dit is niet perse waar in java omdat HashMap at run-time maar 1 implementatie heeft, maar c# heeft at run-time meerdere, aparte implementaties, bijvoorbeeld voor int, double en object. Dus nee, eigenlijk vind ik var mooier, omdat je dan maar 1x List hebt, en de '='-operator maar 1 kant op werkt. :)
Alex) schreef op vrijdag 12 februari 2010 @ 15:31:
Zelfs het resultaat van LINQ-queries gooi ik in een strongly-typed variabele:
Dat doe ik ook, door var te gebruiken. Hou je op jouw manier nog wel schermruimte over? ;) En daarnaast: hoe zie je de consistentie met anonymous types waar dit niet bij kan?

Vitamine D tekorten in Nederland | Corona: wat niet gepost kan worden


  • Alex)
  • Registratie: juni 2003
  • Laatst online: 21-09 13:58
pedorus schreef op vrijdag 12 februari 2010 @ 16:00:
[...]

Dat doe ik ook, door var te gebruiken. Hou je op jouw manier nog wel schermruimte over? ;) En daarnaast: hoe zie je de consistentie met anonymous types waar dit niet bij kan?
Var is in mijn ogen niet strongly-typed. Het mag het dan wel zijn, het ziet er gewoon niet zo uit en doet me alleen maar aan Javascript en PHP denken, daarom gebruik ik het niet. Op 1920x1200 heb ik wel genoeg ruimte :+

Ik vind het gewoon consistent als overal het type gespecificeerd staat... ik ben totnutoe nog geen types tegengekomen waarbij ik per sé 'var' moet gebruiken :-)

We are shaping the future


  • .oisyn
  • Registratie: september 2000
  • Laatst online: 22:50

.oisyn

Moderator Devschuur® / Cryptocurrencies

Demotivational Speaker

Het mag het dan wel zijn, het ziet er gewoon niet zo uit en doet me alleen maar aan Javascript en PHP denken, daarom gebruik ik het niet.
Tja, jouw persoonlijk probleem, en niet die van var :)

Call me cocky, but if there's an alien out there I can't kill I haven't met him and killed him yet. But I can't go in alone. That's why I'm ordering every available ship to report for duty. Anyone else should secure a weapon and fire wildly into the air.


  • pedorus
  • Registratie: januari 2008
  • Niet online
Alex) schreef op vrijdag 12 februari 2010 @ 16:30:
Var is in mijn ogen niet strongly-typed. Het mag het dan wel zijn, het ziet er gewoon niet zo uit en doet me alleen maar aan Javascript en PHP denken, daarom gebruik ik het niet. Op 1920x1200 heb ik wel genoeg ruimte :+
offtopic:
Wil je nooit twee dingen naast elkaar zien dan? :p

Misschien toch ook eens F# proberen, als je bij var teveel richting Javascript/PHP denkt. ;) Maar is het geen paradox dat je R# gebruikt om de boel uit te schrijven, terwijl de mensen achter Resharper dus zelf aanraden om dit juist niet te doen? Link uit de OP (emphasis theirs):
Of course, you can hide this suggestion by using Options / Code Inspection / Inspection Severity, or by using Alt-Enter and selecting "Change severity" option. But what's the deal with implicitly typed locals, anyway? Using var keyword can significantly improve your code, not just save you some typing.
Ik vind het gewoon consistent als overal het type gespecificeerd staat... ik ben totnutoe nog geen types tegengekomen waarbij ik per sé 'var' moet gebruiken :-)
Misschien wordt het dan tijd voor interessantere code. ;) Juist bij linq-queries zie ik het consistentie-oogpunt niet zo (en gebruik ik dus sowieso var); naar alle waarschijnlijkheid gebruiken verreweg de meeste programmeurs daarbij juist var, het is er tenslotte voor verzonnen. var en from/select zijn tegelijkertijd geïntroduceerd, dus waarom zou je de een wel gebruiken (niet consistent met oude code) en de ander niet (ivm consistentie)?

Vitamine D tekorten in Nederland | Corona: wat niet gepost kan worden


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

pedorus schreef op vrijdag 12 februari 2010 @ 16:00:
[...]

Ik vraag me af of er echt concrete voorbeelden zijn van functies die nuttig zijn op die beide types.
Die zijn er wel hoor... :+
C#:
1
2
3
4
5
6
7
8
// vul voor M iets in als bijv. IEnumerable of IObservable
M<A> Join(M<M<A>>);
M<List<A>> Sequence(List<M<A>>);
M<List<B>> MapM(Func<A, M<B>>, List<A>);
M<List<A>> FilterM(Func<A, M<bool>>, List<A>);
M<List<A>> ReplicateM(int, M<A>);
M<B> Ap(M<Func<A, B>, M<A>);
// etc...
Dit lijkt me niet iets dat het type-systeem van c# moet oplossen, maar meer een geval dat de class TestSelect bepaalde interfaces gewoon had moeten implementeren.
Het hele probleem is dus dat je het niet in interfaces kwijt kunt.
Ik zit me af te vragen of een functie niet vaak ook hele andere functionaliteit krijgt heeft als twee classes niet dezelfde interface hebben.
Klopt, de werkelijke functionaliteit hangt ook af van het concrete type. Desondanks zijn er wel bepaalde wetten (die niet door het type system worden gecontroleerd/geforceerd; ook niet in bijv. Haskell) waar je aan moet houden om een beetje zinnige implementaties van Select en SelectMany te kunnen schrijven.
Als de naam dan niet meer klopt, dan is herhaling beter.
Er zijn wel namen te verzinnen. :p
Daarnaast zit je natuurlijk met afnemende meeropbrengsten. Het geval "List<string> stringList = new List<string>();" komt veel vaker voor, en -in mijn ogen- is daar nu een oplossing voor: var. :p
True, en het is ook een aangename toevoeging aan de taal. Neemt niet weg dat ik graag higher-kinded generics in C# wil zien. Het is alleen een lastige kwestie. Zo is bijv. de syntax die ik voorstelde niet helemaal perfect en handig.
[...]
Het lijkt mij 8 (2*3+2),
Typfout van mij:p
(eig. een probleem van veelvuldig editen en vergeten om de gehele code naar de browser te copy/pasten :p)
maar sowieso is het zonder concrete toepassingen mij niet helemaal duidelijk waarom je hier c# en linq voor wil gebruiken,
Func<E, > wordt de Reader monad genoemd en representeert berekeningen die van een gemeenschappelijk omgeving (environment) lezen.

Over het gebruik van LINQ: het is een syntax voor monad comprehensions, dus waarom niet? :p
en al helemaal niet waarom je een operatie op functies ook op IEnumerables wil toepassen. ;)
Bedoel je niet andersom? Waarom ik Select en SelectMany naast IEnumerables ook op functies wil toepassen?

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • pedorus
  • Registratie: januari 2008
  • Niet online
RayNbow schreef op vrijdag 12 februari 2010 @ 17:25:
True, en het is ook een aangename toevoeging aan de taal. Neemt niet weg dat ik graag higher-kinded generics in C# wil zien. Het is alleen een lastige kwestie. Zo is bijv. de syntax die ik voorstelde niet helemaal perfect en handig.
[...]
Over het gebruik van LINQ: het is een syntax voor monad comprehensions, dus waarom niet? :p
Ik heb inmiddels de belangrijkste man achter c# al gequote, maar deze wil ik je ook niet onthouden:
If the word "continuation" causes eyes to glaze over, then the word "monad" induces mental paralysis.
Het zal dus nog wel even duren (of zelfs nooit gebeuren) voordat we hier grootse toevoegingen kunnen verwachten. Je ziet het ook al hoe hier op 'var' gereageerd wordt: veel programmeurs zijn tamelijk conservatief, zeker bij serieuzere code. Ik kan me nog herinneren dat generics in beta waren en ik voorstelde om ze in een subproject te gaan gebruiken: 'waarom zou je dat willen?' :) In 2008, toen R3 vroeg 'Even iets compleet anders: waarom is alles "var" bij jou?' dacht ik precies hetzelfde. Inmiddels begin ik dus meer in dezelfde richting als de R#-ontwikkelaars te denken als het om var gaat. Het nut van 'higher-kinded generics' bij praktische toepassingen ontgaat me nu nog steeds, maar bij var ben ik om. ;)
Bedoel je niet andersom? Waarom ik Select en SelectMany naast IEnumerables ook op functies wil toepassen?
Dat is inderdaad een betere formulering.

Vitamine D tekorten in Nederland | Corona: wat niet gepost kan worden


  • Phyxion
  • Registratie: april 2004
  • Laatst online: 17:18

Phyxion

_/-\o_

Ik gebruik var nooit behalve bij Linq, ik vind het ontzettend onleesbaar, ik wil graag meteen zien welk type het is :)

'You like a gay cowboy and you look like a gay terrorist.' - James May


  • cfern
  • Registratie: oktober 2009
  • Laatst online: 21-09 17:33
Zijn er hier C# programmeurs met codeerafspraken op het werk die het gebruik van var aanmoedigen danwel verbieden? Aangezien niet iedereen gecharmeerd is van var, ben ik wel benieuwd hoe eventuele conflicten binnen teamverband worden aangepakt.

"I'd rather have a full bottle in front of me, than a full frontal lobotomy." (Tom Waits) | PoE


  • Grijze Vos
  • Registratie: december 2002
  • Laatst online: 18-09 23:10
Wij zijn pas eigenlijk sinds kort overgestapt op .NET 3.5, aangezien ons belangrijkste product nog steeds 2.0 was. Binnenkort maar eens een keer discussieren om het gebruik van var in onze coding standards op te nemen.

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

pedorus schreef op zaterdag 13 februari 2010 @ 13:55:
Ik heb inmiddels de belangrijkste man achter c# al gequote, maar deze wil ik je ook niet onthouden:

[...]
Je laat nu net het belangrijkste weg: :p
Perhaps, this is why some have begun inventing more benign names for monads.
Zelfs Simon Peyton-Jones (GHC developer; MS Research) is van mening dat monad een slechte naam is:
Simon Peyton Jones:
Okay. The worst thing about monad is the name.

Richard Campbell:
They sound far worse than they are.

Simon Peyton Jones:
Yeah, that's why. The name is very off-putting because it comes from something mathematical. I'm on record as saying we should have called them warm, fuzzy things.
Het zal dus nog wel even duren (of zelfs nooit gebeuren) voordat we hier grootse toevoegingen kunnen verwachten. Je ziet het ook al hoe hier op 'var' gereageerd wordt: veel programmeurs zijn tamelijk conservatief, zeker bij serieuzere code.
Mjah, conservatisme zie je helaas in de gehele geschiedenis van de informatica terug.
Ik kan me nog herinneren dat generics in beta waren en ik voorstelde om ze in een subproject te gaan gebruiken: 'waarom zou je dat willen?' :)
Als een bepaalde feature nog in beta was, dan zou ik me wel kunnen voorstellen dat je het nog niet zou toepassen in een (sub)project.
In 2008, toen R3 vroeg 'Even iets compleet anders: waarom is alles "var" bij jou?' dacht ik precies hetzelfde. Inmiddels begin ik dus meer in dezelfde richting als de R#-ontwikkelaars te denken als het om var gaat.
Dat was dus een probleem van gewenning. Als je gewend bent om bij elke variabele een expliciete typeannotatie te zien, dan moet je leren die gewenning ongedaan te maken. :)
Het nut van 'higher-kinded generics' bij praktische toepassingen ontgaat me nu nog steeds, maar bij var ben ik om. ;)
Misschien zijn er twee dingen nodig om 't nut te kunnen inzien van higher-kinded generics. Ten eerste is de notatie. Je moet jezelf wel makkelijk kunnen uitdrukken in een taal en ook ermee kunnen spelen (i.e., uitvoerbare code). Relevant stukje conversatie op IRC een tijdje terug:
quote: IRC
<RayNbow> <luite> geeft trouwens wel aan hoeveel notatie uitmaakt <-- hoe bedoel je precies?
<RayNbow> als de notatie te lastig wordt... dat mensen dan minder geneigd zijn om 't als bruikbaar te zien?
<luite> ja idd, als notatie 'natuurlijk' is ben je veel sneller geneigd een abstractie te accepteren en als bruikbaar te zien
Ten tweede is het belangrijk om de juiste patronen te kennen en kunnen herkennen. Als je bijvoorbeeld inziet dat iets zich gedraagt als een monad, dan weet je dat je in C# de LINQ syntax kunt gebruiken.

Ter illustratie, probabilistische netwerken vormen een monad en we kunnen dus de LINQ syntax gebruiken. Het voorbeeld dat ik ga bespreken heb ik uit deze (redelijk toegankelijke) talk, die het op zijn beurt van Wikipedia heeft:
Suppose that there are two events which could cause grass to be wet: either the sprinkler is on or it's raining. Also, suppose that the rain has a direct effect on the use of the sprinkler (namely that when it rains, the sprinkler is usually not turned on). Then the situation can be modeled with Bayesian network. All three variables have two possible values T (for true) and F (for false).
De kans dat het gras nat is kan met het volgende diagram worden weergegeven:


(klikbaar voor iets grotere versie)

De pijlen in dit diagram laten zien hoe de informatie stroomt. Uit de stochast "Rain" vloeit de informatie of het wel of niet regent en draagt in het diagram het label r. Zoals je kunt zien bereikt deze informatie de stochasten "Sprinkler" en "Grass wet". Op dezelfde wijze stroomt er informatie van "Sprinkler" naar "Grass wet". De informatie of het gras nat is vloeit van "Grass wet" uit het gehele diagram.

We kunnen ook de vraag stellen: "wat is de kans dat het regent, gegeven het feit dat gras nat is?". Deze vraag wordt in het volgende diagram worden weergegeven:



Het diagram is vrijwel hetzelfde als voorheen, alleen nu voegen we een bewering toe dat de informatie van "Grass wet" waar moet zijn (="Grass is wet") en i.p.v. of het gras nat is laten we de informatie uit "Rain" naar buiten vloeien.


Deze diagrammen kun je 1-op-1 vertalen naar code. We liften eerst de booleans true en false naar een rijker type. Dit scheelt namelijk straks wat typwerk:
C#:
1
2
static Prob PFalse = new Prob(false);
static Prob PTrue = new Prob(true);


Vervolgens implementeren we de kanstabellen:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static Prob Rain()
{
    return 0.2 * PTrue + 0.8 * PFalse;
}

static Prob Sprinkler(bool raining)
{
    return
        !raining  ?  0.40 * PTrue + 0.60 * PFalse  :
        raining   ?  0.01 * PTrue + 0.99 * PFalse  :
        null;
}

static Prob GrassWet(bool sprinkler, bool raining)
{
    return
        !sprinkler  &&  !raining  ?  PFalse                        :
        !sprinkler  &&  raining   ?  0.80 * PTrue + 0.20 * PFalse  :
        sprinkler   &&  !raining  ?  0.90 * PTrue + 0.10 * PFalse  :
        sprinkler   &&  raining   ?  0.99 * PTrue + 0.01 * PFalse  :
        null;
}

(Deze code kan korter, maar dan mis je de tabelstructuur)

Uiteindelijk kun je elk van de twee diagrammen beschrijven met een LINQ query:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static void Main(string[] args)
{
    var grasswet = from r in Rain()
                   from s in Sprinkler(r)
                   from g in GrassWet(s, r)
                   select g;
    
    var diditrain = from r in Rain()
                    from s in Sprinkler(r)
                    from g in GrassWet(s, r)
                    where g
                    select r;
    
    Console.WriteLine(grasswet);  // <0,44838:True, 0,55162:False>
    Console.WriteLine(diditrain); // <0,16038:True, 0,288:False>
    Console.WriteLine(diditrain / diditrain.Norm1()); // <0,357687675632276:True, 0,642312324367724:False>
    Console.ReadKey();
}

De from-clauses labelen de informatie die uit een stochast stroomt, zodat we deze informatie aan andere stochasten kunnen doorgeven. Met een where-clause kunnen we "gegeven het feit dat..." modeleren en met select-clause kunnen we opgeven welke informatie uit het diagram vloeit.

[Voor 0% gewijzigd door RayNbow op 28-03-2011 18:16. Reden: link fix]

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • pedorus
  • Registratie: januari 2008
  • Niet online
RayNbow schreef op maandag 22 februari 2010 @ 00:17:
De from-clauses labelen de informatie die uit een stochast stroomt, zodat we deze informatie aan andere stochasten kunnen doorgeven. Met een where-clause kunnen we "gegeven het feit dat..." modeleren en met select-clause kunnen we opgeven welke informatie uit het diagram vloeit.
Ik heb het even uitgeprobeert met de code van http://tinypaste.com/d8f77 en het werkt goed inderdaad. Ik denk enkel dat je voor praktische toepassingen dit niet direct in c# wilt hebben, omdat je dan ongeveer vanuit je UI steeds de c#-compiler moet gaan aanroepen ofzo. Je zal meestal een willekeurig netwerk willen kunnen doorrekenen in je programma, niet eentje waarvan de attributen en relaties al vast staan (en als dit niet zo is, zul je waarschijnlijk juist nog specifiekere code willen hebben).

De code op tinypaste is trouwens een mooi voorbeeld van dat de duidelijkheid van var niet perse door de kortheid komt. Ze doen daar exact hetzelfde als wat jij doet:
C#:
1
2
3
4
            var grasswet = from r in Rain()
                           from s in Sprinkler(r)
                           from g in Grass(s, r)
                           select g;

Terwijl het daar met typenaam korter is, maar in mijn ogen minder leesbaar/handig:
C#:
1
2
3
4
            V grasswet = from r in Rain()
                         from s in Sprinkler(r)
                         from g in Grass(s, r)
                         select g;

Vitamine D tekorten in Nederland | Corona: wat niet gepost kan worden


  • RayNbow
  • Registratie: maart 2003
  • Laatst online: 18:18

RayNbow

Kirika <3

pedorus schreef op maandag 22 februari 2010 @ 20:47:
[...]

Ik heb het even uitgeprobeert met de code van http://tinypaste.com/d8f77 en het werkt goed inderdaad.
[...]
De code op tinypaste is trouwens een mooi voorbeeld van dat de duidelijkheid van var niet perse door de kortheid komt. Ze doen daar exact hetzelfde als wat jij doet:
C#:
1
2
3
4
            var grasswet = from r in Rain()
                           from s in Sprinkler(r)
                           from g in Grass(s, r)
                           select g;

Terwijl het daar met typenaam korter is, maar in mijn ogen minder leesbaar/handig:
C#:
1
2
3
4
            V grasswet = from r in Rain()
                         from s in Sprinkler(r)
                         from g in Grass(s, r)
                         select g;
Die tinypaste is een oude versie van m'n code. :+ Op een gegeven moment vond ik Prob een betere naam dan alleen V van vector.

Edit: hier is een paste van de recentste versie.
Ik denk enkel dat je voor praktische toepassingen dit niet direct in c# wilt hebben, omdat je dan ongeveer vanuit je UI steeds de c#-compiler moet gaan aanroepen ofzo. Je zal meestal een willekeurig netwerk willen kunnen doorrekenen in je programma, niet eentje waarvan de attributen en relaties al vast staan
De diagrammen waren een visualisatie van het voorbeeld, maar ook in zekere zin van de code. Als je een GUI wilt bouwen waarin de gebruiker zelf het netwerk visueel kan construeren, dan zal je waarschijnlijk o.a. elke node door een object laten representeren.

Maar zelfs in die andere representatie blijft de monadische structuur bestaan.
(en als dit niet zo is, zul je waarschijnlijk juist nog specifiekere code willen hebben).
Als alles vast staat kun je eigenlijk aan constant-folding doen. :p

[Voor 4% gewijzigd door RayNbow op 22-02-2010 21:39]

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


  • Ankona
  • Registratie: mei 2014
  • Laatst online: 21:41
Zo even een oud topic onder het stof vandaan gehaald en een rotschop gegeven.

We zijn inmiddels een jaar of 10 verder maar deze discussie voer ik op mijn werk nog steeds vaak. Zelf ben ik absoluut geen voorstander van het gebruik van var anders dan voor anonymous types. Microsoft adviseert het gebruik ervan mits aan de assignment direct te zien is om welk type het gaat. (dus aanroepen van een constructor, niet bij het aanroepen van een functie)
Resharper maakt er helemaal een puinhoop van, die adviseert het altijd met als gevolg onleesbare code (je weet niet waar je mee aan het werk bent) die gevoelig is voor onverwacht gedrag (als die functie aangepast wordt kan het zo zijn dat de compiler het nog steeds prima vindt maar je werkt ineens met een heel ander type)

Spottend zeg ik vaak dat var ideaal is voor developers die geen idee hebben wat ze aan het doen zijn.

Sommige collega's noemen nog als voordeel dat als je een rijtje declaraties hebt, ze met var zo mooi recht uitgelijnd staan. Tja, dan schrijf je meestal slechte code met veel te veel responsibility.

Op zich kan ik nog wel redelijk leven met de guideline van Microsoft al ben ik niet overtuigd van de voordelen. (Ok, bij lange type namen kan het wat lange regels met herhaling van zetten opleveren. Dan valt er wel wat voor var te zeggen - uit consistentie oogpunt verkies ik het dan om ook in die gevallen geen var te gebruiken maar dat is mijn voorkeur.)

Weet iemand de echte reden waarom Microsoft en zeker Resharper zulke fans zijn van var? Sommige teams leunen blind op deze aanbevelingen wat discussies erg lastig maakt.

alles kan off-topic

Pagina: 1 2 Laatste


Apple iPhone SE (2020) Microsoft Xbox Series X LG CX Google Pixel 4a CES 2020 Samsung Galaxy S20 4G Sony PlayStation 5 Nintendo Switch Lite

'14 '15 '16 '17 2018

Tweakers vormt samen met Hardware Info, AutoTrack, Gaspedaal.nl, Nationale Vacaturebank, Intermediair en Independer DPG Online Services B.V.
Alle rechten voorbehouden © 1998 - 2020 Hosting door True