[C#][Algemeen] Hoe variabelen declareren?

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

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Jan_V
  • Registratie: Maart 2002
  • Laatst online: 22:50
Sinds kort heb ik de software ReSharper 3.1 geinstalleerd bij m'n VS2008 installatie, aangezien ik vaak lees dat het een handig hulpmiddel is.
Dit kan ik nu beamen, afgezien dat het de solution behoorlijk vertraagd, is het een handig hulpmiddel.
Gisteren was ik m'n code aan het optimizen/cleanen en kwam ReSharper met de suggestie/melding dat ik een variabele beter in de scope kon declareren in plaats van er buiten.
Het gaat om het volgende voorbeeld
code:
1
2
3
4
5
6
DossierInfo dossierInfo;
foreach (TestInfo testInfo in testItems)
{
      dossierInfo = new DossierInfo();
      //bladiebladiebla, doe iets.
}

ReSharper vind het mooier als het zo wordt gedefinieerd
code:
1
2
3
4
5
foreach (TestInfo testInfo in testItems)
{
      DossierInfo dossierInfo = new DossierInfo();
      //bladiebladiebla, doe iets.
}


Persoonlijk verkies ik de bovenste optie. Ook was m'n gedachte er achter dat bij de bovenste optie telkens hetzelfde geheugenblok wordt gebruikt en dus efficienter zou (kunnen) zijn. Dit van het geheugenblok heb ik zelf verzonnen, aangezien ik dat in C++ wel zou doen wanneer dit zou voorkomen.
Nu wordt ik echter in verwarring gebracht. Voor scoping is het misschien wel handiger om de variabele in de foreach-scope te definieren, maar dan wordt er sowieso continu een nieuw object gemaakt.
De GC zal dat allemaal wel weer opruimen, maar toch....

M'n vraag is dus, welke optie verkiezen jullie en waarom?
De mensen van JetBeans hebben er vast zelf ook wel over nagedacht, vandaar dat ik zoiets heb van het advies op te volgen, hoewel ik het niet mooi vind.

PS: Ik heb het ook aan een collega van me voorgelegd. Die gebruikt over het algemeen ook de eerste optie en vroeg zich nu ook af waarom de 2e optie wordt verkozen door ReSharper.

[ Voor 5% gewijzigd door Jan_V op 21-01-2008 14:25 ]

Battle.net - Jandev#2601 / XBOX: VriesDeJ


Acties:
  • 0 Henk 'm!

  • AtleX
  • Registratie: Maart 2003
  • Niet online

AtleX

Tyrannosaurus Lex 🦖

Nu is testInfo ook buiten je loop te benaderen, na de loop bevat deze namelijk nog het laatste item. Als je 'm in de loop declareert beperkt dat de scoop tot de loop, waarna de garbage collector het op kan ruimen. Denk ik.

Je argument over geheugen allocatie klopt niet, de compiler/JIT van .NET zorgt er gewoon voor dat je elke keer hetzelfde stuk geheugen gebruikt.

Acties:
  • 0 Henk 'm!

Anoniem: 105463

Ik verkies zelf de methode van ReSharper (ookal heb ik dat nog nooit gebruikt). De variabele dossierInfo heeft alleen betekenis binnen de for-loop en zal daarbuiten niet gebruikt worden. Voor het overzicht declareer ik hem dan ook in de for-loop.

Acties:
  • 0 Henk 'm!

  • Dennis
  • Registratie: Februari 2001
  • Laatst online: 20:59
Is het niet zo dat ReSharper dat aangeeft omdat hij ziet dat je hem buiten die for-loop toch niet gebruikt? Want daar gaat het tenslotte om (zie ook ProFox).

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:30
Ik denk dat de CLR wel slim genoeg is om de beste optie te verkiezen bij het alloceren van geheugen blokken.
Zowiezo zit je met een managed heap die ervoor zorgt dat het geheugen dat je alloceerd contiguous is.

Ik vind de optie die Resharper je aanbiedt, beter.
Waarom ? Aangezien je de variable binnen die loop alloceerd, ga ik er van uit dat je die variable buiten die loop nergens meer nodig hebt.
Waarom zou je ze dan buiten die scope definieren ?
Zo heb je meer kans op fouten; buiten je loop kan je nl. nog iets met dat object doen, terwijl dat waarschijnlijk de bedoeling niet zal zijn...
maar dan wordt er sowieso continu een nieuw object gemaakt.
De GC zal dat allemaal wel weer opruimen, maar toch....
Ehm, bij jouw optie wordt er ook bij iedere iteratie een nieuw object gemaakt hoor ...
De GC zal trouwens pas opruimen als het nodig is.

[ Voor 9% gewijzigd door whoami op 21-01-2008 14:31 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

dossierInfo wordt in de loop gewoon herbruikt als reference naar DossierInfo in de CLR. De CLR herkent dergelijke loop constructies. Zolang de nieuwe inhoud even groot is als de oude inhoud, zal de CLR altijd de bestaande variabele op de stack aanhouden. Omdat de referentie in principe 4 bytes inneemt, zal een nieuwe referentie opnieuw 4 bytes gebruiken en kan dus de variabele worden hergebruikt. value types (int, string, double, references, etc) worden op de stack opgeslagen. Object instanties worden bewaard op de heap. Omdat dossierInfo eigenlijk alleen naar een ander object op de heap verwijst kan deze dus worden hergebruikt.

Daarbij maakt het niet uit of dossierInfo al buiten de loop defineerd wordt. Wordt die erbuiten gedefineerd, dan zal de reference langer in gebruik blijven (laatste item als loop blijft immers als reference aanwezig) en duurt het langer voordat de CLR hem als unreferenced markeert zodat de garbabe collector de reference op de stack kan verwijderen.

Daarbij lijkt mij de kans de je buiten de loop nog iets met dossierInfo doet erg klein. Immers zul je alle akties binnen de loop uitvoeren en niet alleen op het laatste item. Daarnaast is het gewoon 'netjes' om je variabele in de juiste scope te defineren.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Niemand_Anders schreef op maandag 21 januari 2008 @ 14:48:
value types (int, string, double, references, etc) worden op de stack opgeslagen.
Op zich gelijk, echter worden strings AFAIK wel op de heap opgeslagen. Ze gedragen zich echter als valuetypes aangezien ze immutable zijn.

“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.”


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:30
een string is idd een reference type , en staat op de heap

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
De laatste optie van Reshaper lijkt mij beter eigenlijk. De code in dit geval anders opschrijven om efficiënter met geheugen om te gaan is onzin, zie ook de andere posts. Zeker ook omdat je de exacte implementaties van toekomstige compilers toch nog niet weet.

Er zijn volgens mij twee belangrijke redenen om de laatste variant te gebruiken. De eerste is dat het er leesbaarder op wordt. Je gebruikt een regel minder, en daarnaast staan dingen die bij elkaar horen op dezelfde regel. Minder kans op fouten dus. De tweede reden is dat de scope goed staat, waardoor de variabele na de loop niet meer per ongeluk kan worden gebruikt.

Ook als je meerdere loops hebt met dezelfde situatie, dan zou ik voor de tweede optie gaan.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 12:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik zie een hoop gezever over garbage collection en geheugen reservering e.d., maar dat zijn allemaal onzin argumenten :). Het enige verschil tussen de twee vormen is je eigen semantiek die je eraan koppelt. Buiten de loop definieren betekent dat je 'm ook buiten de loop kunt accessen. Wil je dat? Hij is mogelijk niet geinitialiseerd (en dus null) als de loop geen enkele iteratie doorloopt. Anders heeft hij de waarde van de laatste iteratie. Is dat zinnige informatie die je wilt gebruiken? Wat je jezelf af moet vragen is: is het de bedoeling dat ik de variabele mogelijk nog buiten de loop kan gebruiken? Zo ja, dan definieer je 'm buiten de loop. Zo niet, dan niet.

Wat performance en GC e.d. betreft maakt het namelijk geen drol uit. De VM is slim genoeg om te zien dat als je de variabele verderop niet meer gebruikt (leest), dat hij dus ook wel opgeruimd kan worden voordat de variabele definitief uit scope is verdwenen. Ook is het niet zo dat die variabele een plek op de stack reserveert - een variabele die niet wordt gebruikt voor de volgende assignment hoeft geen stackspace in te nemen, en na de volgende assignment is het niet per se dezelfde plek op de stack als voorheen.

Je kunt overigens wel gewoon optimizen door dingen buiten de lus te definieren. Als je bijvoorbeeld een dynamische array nodig hebt elke iteratie. Door steeds gebruik te maken van dezelfde container die je iedere keer cleart, hoeft hij mogelijk niet steeds opnieuw geheugen te alloceren - als je de vorige iteratie 10 elementen nodig had, en nu nog maar 4, dan gebruikt hij gewoon het geheugen dat al gereserveerd was. Maar dat is semantisch heel wat anders dan wat je nu doet, omdat je nu in feite de variabele elke iteratie opnieuw assignt, waardoor het in feite net zo goed elke keer een andere variabele had kunnen zijn.

Dit werkt natuurlijk anders dan in C++, wat gebruik maakt van deterministic finalization. Oftewel, het is gedefinieerd dat een variabele ook echt wordt opgeruimd zodra hij buiten scope gaat. In dat geval kun je je afvragen of een assignment duurder is dan een destructor gevolgd door een constructor. En ook of je de destructor wilt runnen na de loop, of pas aan het eind van de functie. Maar dat is natuurlijk alleen van belang bij objecten zonder triviale ctors en dtors.

[ Voor 60% gewijzigd door .oisyn op 21-01-2008 15:56 ]

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


Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

rwb schreef op maandag 21 januari 2008 @ 15:15:
[...]

Op zich gelijk, echter worden strings AFAIK wel op de heap opgeslagen. Ze gedragen zich echter als valuetypes aangezien ze immutable zijn.
Excuus. System.String in inderdaad een class en geen structure. Mijn fout. Verder zijn strings wel mutable als de inhoud van de nieuwe waarde even groot is als de oorspronkelijke waarde. Alleen als de string korter of langer is dan de oorspronkelijke waarde moet de CLR de instantie op de heap kopieren en string de juiste lengte te geven.

C#:
1
2
3
4
string a = "hello";
a = "world"; // <-- veroorzaakt geen reorganisatie van de heap; inhoud van 'a' blijft 5 bytes.
a = "tweakers"; //<-- veroorzaakt wel reorganisatie van de heap omdat 'a' ineens van 5 naar 8 bytes gaat, 'a' krijgt nieuwe reference naar heap.
a = "net"; // ook hier reorganisatie omdat lengte van 8 naar 3 bytes gaat

Daarom is het verstandiger om een StringBuilder instance te gebruiken als je veel string operaties moet uitvoeren.

C#:
1
string b = "hello" + " " + "world";

Bovenstaand wordt door de Microsoft en Mono compiler al automatisch omgezet naar 1 string als optimalisatie. De DotGnu c# compiler heeft deze optimalisatie niet.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:30
strings zijn immutable, of toch als immutable geimplementeerd.
Je hebt geen enkele string functie die op de string zelf werkt. Replace bv , levert altijd een nieuwe string op.

Maar, dit gaat offtopic

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Jan_V
  • Registratie: Maart 2002
  • Laatst online: 22:50
Bedankt voor de vele reacties.
Voor zover ik het hier lees is het inderdaad beter om een variabele in de juiste scope te definieren, aangezien het geen voordeel biedt om hem daarbuiten de definieren (eerder nadelen).
In dit geval, en in vele andere gevallen, is het toch niet nodig dat de variabele buiten de betreffende foreach-loop beschikbaar is.

Vanaf nu zal ik me dan ook maar aan de ReSharper suggestie houden en alles gewoon in z'n eigen scope aanmaken.

Battle.net - Jandev#2601 / XBOX: VriesDeJ


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 25-04 15:56
AtleX schreef op maandag 21 januari 2008 @ 14:26:
Je argument over geheugen allocatie klopt niet, de compiler/JIT van .NET zorgt er gewoon voor dat je elke keer hetzelfde stuk geheugen gebruikt.
(dit wordt nog enkele keren gezegd)

Zelf schrijf ik een 3D rendering programma in C# die dus ook door de .NET JiT compiler gecompileerd wordt, en ik kan je vertellen dat in high-performance applicaties het wel degelijk tragers is om elke keer de variabele opnieuw te declareren. De opbouwtijd van het frame werd toch zeker een paar procent vertraagd.

Verder weet ik niet hoe super belangrijk jouw foreach loop moet zijn qua snelheid, en hoe vaak deze gelooped wordt. (In mijn app was het voor elk frame 3x, dus dat kwam toendertijd neer op zo'n 700x per seconde opnieuw de variabele declareren.)

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • AtleX
  • Registratie: Maart 2003
  • Niet online

AtleX

Tyrannosaurus Lex 🦖

roy-t schreef op dinsdag 22 januari 2008 @ 18:16:
[...]


(dit wordt nog enkele keren gezegd)

Zelf schrijf ik een 3D rendering programma in C# die dus ook door de .NET JiT compiler gecompileerd wordt, en ik kan je vertellen dat in high-performance applicaties het wel degelijk tragers is om elke keer de variabele opnieuw te declareren. De opbouwtijd van het frame werd toch zeker een paar procent vertraagd.

Verder weet ik niet hoe super belangrijk jouw foreach loop moet zijn qua snelheid, en hoe vaak deze gelooped wordt. (In mijn app was het voor elk frame 3x, dus dat kwam toendertijd neer op zo'n 700x per seconde opnieuw de variabele declareren.)
Ongetwijfeld, ik heb me daar nooit echt in verdiept. Maar in dit geval betreft het alleen maar een assignment aan een variabele. Aangezien een object op de heap leeft en deze variabele dus alleen pointer is zou het dus niet bepaald een probleem moeten zijn. Het lijkt me sterk dat bij elke assignment eerst de garbage collector langskomt om die pointer te destroyen en daarna nieuw geheugen te alloceren. Nogmaals, echt veel verstand heb ik er niet van maar dit lijkt me de meest logische werkwijze.

[ Voor 11% gewijzigd door AtleX op 22-01-2008 19:31 ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Aangezien het op de stack staat zal de GC er niet zoveel mee te maken heeft.

Ik vraag me af of het niet wat anders was waardoor het trager werd. Ik kan me niet voorstellen dat in de volgende 2 stukjes verschil zit nadat het gejit is.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
object var = new object();

for(int i=0; i < 10; i++)
{
    var = new object();
    //doe wat met var
}
//Hierna word var niet meer gebruikt

//en

for(int i=0; i < 10; i++)
{
    object var = new object();
    //doe wat met var
}


Als er al verschil is dan is het verschil dat er in het ene geval telkens een var op de stack gepushed moet worden en bij de andere gewoon de waarde hoger op de stack gewijzigd kan worden ( de pointer naar de heap want in beide gevallen word er elke loop een nieuw object op de heap gemaakt ), maar dat verschil lijkt me ook te verwaarlozen.

“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.”


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 12:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

@roy-t: Kun je eens een voorbeeld geven waarbij jij ziet dat het performance kost? In het geval van de TS geloof ik dat namelijk gewoon niet :). Zoals AtleX al zegt, de assignment is sowieso nodig en die stackspace loopt niet weg. Maar je zou natuurlijk wel een case kunnen bedenken waarin het wel scheelt, omdat de variabele in de lus steeds opnieuw geinitialiseerd moet worden zodra er een pad bestaat waarin je niet schrijft voordat je leest (oftewel, die initiasatie moet zichtbaar kunnen zijn).

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


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 25-04 15:56
.oisyn schreef op dinsdag 22 januari 2008 @ 19:58:
@roy-t: Kun je eens een voorbeeld geven waarbij jij ziet dat het performance kost? In het geval van de TS geloof ik dat namelijk gewoon niet :). Zoals AtleX al zegt, de assignment is sowieso nodig en die stackspace loopt niet weg. Maar je zou natuurlijk wel een case kunnen bedenken waarin het wel scheelt, omdat de variabele in de lus steeds opnieuw geinitialiseerd moet worden zodra er een pad bestaat waarin je niet schrijft voordat je leest (oftewel, die initiasatie moet zichtbaar kunnen zijn).
@ Oisyn en Atlex.

Hmm ik zal is kijken of ik het kan reproduceren, ik moet zeggen dat het niet de meest geweldige code was die ik ooit geschreven had, maar het viel me toen erg op dat er toch een duidelijke winst zat in die variabele anders te declareren.

Wel deed ik veel meer met die variabele en werd deze bijvoorbeeld ook doorgegeven aan verschillende andere classes/methods van uit de loop.

Het verhaal van Atlex klinkt erg aannemelijk, ik denk dat het meer een specifiek iets in mijn programma was, maar het was wel interessant om te zien, en toch even om aan te geven dat je het eigenlijk gewoon even zou moeten testen, geen (merkbaar) verschil? Decla het dan in de loop omdat dat gewoon netter is :).

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • justice strike
  • Registratie: Juni 2001
  • Laatst online: 30-04 11:48
In java kun je dezelfde constructie maken.

De tweede optie is netter. Het kost geen extra geheugen, want het is een reference. Daarbij isoleer je het object van de rest van de functie wat het leesbaarder maakt en voorkom je dat er fouten gemaakt worden.

Zou je het object ergens anders nog gebruiken dan zou je het kunnen doen. Je kunt de vergelijking ook een beetje trekken met globale references vs. lokale references.

U can call me sir.... or justice as long as u bow down ;)


Acties:
  • 0 Henk 'm!

  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 21-04 16:18
justice strike schreef op woensdag 23 januari 2008 @ 11:02:
In java kun je dezelfde constructie maken.

De tweede optie is netter. Het kost geen extra geheugen, want het is een reference. Daarbij isoleer je het object van de rest van de functie wat het leesbaarder maakt en voorkom je dat er fouten gemaakt worden.

Zou je het object ergens anders nog gebruiken dan zou je het kunnen doen. Je kunt de vergelijking ook een beetje trekken met globale references vs. lokale references.
Met het object ergens anders nog een keer gebruiken bedoel je een ander object met dezelfde naam neem ik aan (want dat zou alleen op kunnen gaan voor de tweede optie)? Want dat kan in C# dus niet. Om ambiguïteit te voorkomen dwingt de compiler dat af.

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


Acties:
  • 0 Henk 'm!

  • AtleX
  • Registratie: Maart 2003
  • Niet online

AtleX

Tyrannosaurus Lex 🦖

rwb schreef op dinsdag 22 januari 2008 @ 19:57:
Aangezien het op de stack staat zal de GC er niet zoveel mee te maken heeft.
Ja, foutje. :+ Die pointer wordt natuurlijk gewoon eraf ge-pop()-t.

Acties:
  • 0 Henk 'm!

  • justice strike
  • Registratie: Juni 2001
  • Laatst online: 30-04 11:48
riezebosch schreef op woensdag 23 januari 2008 @ 11:40:
[...]

Met het object ergens anders nog een keer gebruiken bedoel je een ander object met dezelfde naam neem ik aan (want dat zou alleen op kunnen gaan voor de tweede optie)? Want dat kan in C# dus niet. Om ambiguïteit te voorkomen dwingt de compiler dat af.
je kunt het object gewoon ergens anders gebruiken in de eerste optie. Immers heb je de reference nog.

In de tweede optie kun je alleen idd de reference van het object gebruiken om naar een ander object te verwijzen. Eigenlijk is het niet eens meer dezelfde reference aangezien je de reference weer opnieuw moet maken.

U can call me sir.... or justice as long as u bow down ;)


Acties:
  • 0 Henk 'm!

  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 21-04 16:18
justice strike schreef op woensdag 23 januari 2008 @ 12:01:
[...]


je kunt het object gewoon ergens anders gebruiken in de eerste optie. Immers heb je de reference nog.

In de tweede optie kun je alleen idd de reference van het object gebruiken om naar een ander object te verwijzen. Eigenlijk is het niet eens meer dezelfde reference aangezien je de reference weer opnieuw moet maken.
Dat bedoel ik dus, dit mag in C# dus niet:
C#:
1
2
3
4
5
6
for (long i = 0; i < max; i++)
{
    object o = new object();
}

object o = new object();
A local variable named 'o' cannot be declared in this scope because it would give a different meaning to 'o', which is already used in a 'child' scope to denote something else

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 12:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Hoe is dat in hemelsnaam ambigu? Dit is wel ambigu:
C#:
1
2
3
4
5
6
7
object o = new object();

for (long i = 0; i < max; i++) 
{ 
    object o = new object(); 
    o.doeIets();  // welke o?
}


Wel een beetje loos als je het mij vraagt.

[ Voor 18% gewijzigd door .oisyn op 23-01-2008 13:33 ]

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


Acties:
  • 0 Henk 'm!

  • AtleX
  • Registratie: Maart 2003
  • Niet online

AtleX

Tyrannosaurus Lex 🦖

Bij een for() loop is de scoop van de variabele niet beperkt tot de loop maar tot de parent scoop. Beetje raar inderdaad. Het gedrag dat jij laat zien is logischer. Alhoewel, het lijkt me logisch dat hij bij de variabele o in de loop al een error moet geven.

Eerste zinnetje van .oisyn's post gemist. :X

[ Voor 46% gewijzigd door AtleX op 23-01-2008 13:36 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 12:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik gaf de ambiguiteit weer, niet wanneer de compiler error op zou treden :). In de definitie is ie nog niet ambigu omdat je weet dat je daar een nieuwe 'o' introduceert.

In C++ is dit overigens niet ambigu en wordt er altijd vanuit de huidige nesting naar boven gezocht. Overigens bestaat dezelfde ambiguïteit in C# ook op een ander niveau, en daar mag het weer wel:
C#:
1
2
3
4
5
6
7
8
9
class Bla
{
    int bla;

    void func()
    {
        object bla = new Object();  // mag wel 8)7
    }
}

[ Voor 73% gewijzigd door .oisyn op 23-01-2008 13:37 ]

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


Acties:
  • 0 Henk 'm!

  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 21-04 16:18
.oisyn schreef op woensdag 23 januari 2008 @ 13:29:
Hoe is dat in hemelsnaam ambigu? Dit is wel ambigu:
C#:
1
2
3
4
5
6
7
object o = new object();

for (long i = 0; i < max; i++) 
{ 
    object o = new object(); 
    o.doeIets();  // welke o?
}


Wel een beetje loos als je het mij vraagt.
In feite is het inderdaad niet ambigu. Maar dacht wel dat ze het expres niet toestaan om problemen te voorkomen. Vroeger, toen al mijn variabelenamen nog maximaal 1 karakter lang waren, heb ik me er wel aan geërgerd dat ik iedere loop een nieuwe moest verzinnen :P

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 12:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nou ja dus niet iedere loop, dit mag blijkbaar wel
C#:
1
2
3
4
5
6
7
8
9
for (long i = 0; i < max; i++)  
{  
    object o = new object();  
}

for (long i = 0; i < max; i++)  
{  
    object o = new object();  
}


i en o worden dubbel gebruikt. Maar de twee scopes zijn dan ook siblings, geen parent-child relatie.

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


Acties:
  • 0 Henk 'm!

  • HawVer
  • Registratie: Februari 2002
  • Laatst online: 21-04 23:11
Ik dacht ik ga eens wat testen draaien en dan door middel van ildasm de code omzetten naar msil. Tijdens het compileren wordt c# code omgezet naar msil code welke weer vertaald wordt naar systeem specifieke code dmv jit compiler. Ildasm draait dit proces om en genereert van dll's msil code.

Zie:
http://msdn2.microsoft.co...rary/c5tkafs1(VS.71).aspx

Lokale variabelen
Testrun 1
C#:
1
2
3
4
5
object c;
for (int i = 1; i < 10; i++)
{
    c = new object();
}

vs
C#:
1
2
3
4
for (int i = 1; i < 10; i++)
{
    object c = new object();
}

Maakt volgens de msil code geen ruk uit. Als je dmv ildasm beide versies gaat bekijken dan zie je dat beide versies het object op dezelfde plaats creeeren. Dus qua performance zal het voor objecten niet uitmaken.

Testrun 2
De tweede run gaat het object nog een keer gebruiken met dezelfde naam binnen de scope van een loop.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int n;

for (int i = 1; i < 10; i++)
{
    n = i;
    Console.WriteLine(n);
}

for (int i = 1; i < 10; i++)
{
    n = i;
    Console.WriteLine(n);
}
}

vs
C#:
1
2
3
4
5
6
7
8
9
10
11
for (int i = 1; i < 10; i++)
{
    int n = i;
    Console.WriteLine(n);
}

for (int i = 1; i < 10; i++)
{
    int n = i;
    Console.WriteLine(n);
}

Voorbeeld 1 locals stacksize = 3
Voorbeeld 2 locals stacksize = 4

Testrun 3
Dit geldt ook voor classen :o
code:
1
2
3
    .locals init ([0] object n,
             [1] int32 i,
             [2] int32 V_2)

vs
code:
1
2
3
4
    .locals init ([0] int32 i,
             [1] object n,
             [2] int32 V_2,
             [3] object V_3)

Aantal notes, het zou kunnen dat de jit compiler nog wat optimization doet. De ildasm kan ook slechte code genereren.

http://hawvie.deviantart.com/


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Maar 1 extra refference op je stack zal echt geen bergen verschil maken natuurlijk. En in het geval wat je aanhaalt word de variabele later natuurlijk nog gebruikt ( al kan het natuurlijk wel geoptimaliseerd worden omdat er altijd eerst een write komt voor een read )

“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.”


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
De ildasm kan ook slechte code genereren.
Lijkt me sterk, hij zet IL opcodes direct om in een textueel format.

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


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 12:36

.oisyn

Moderator Devschuur®

Demotivational Speaker

rwb schreef op woensdag 23 januari 2008 @ 22:34:
Maar 1 extra refference op je stack zal echt geen bergen verschil maken natuurlijk.
Idd, maar de IL zegt in feite nog niets. De IL compiler zal niet (hevig) optimizen, dus die definieert voor elke variabele domweg een entry. De VIM zal de IL analyseren en ontdekken dat de lifetime van een variabele beperkt is - een variabele hoeft alleen maar te bestaan tussen een write en de laatste read vóór de volgende write. Op die manier kunnen meerdere variabelen dezelfde stackspace gebruiken, of kan een enkele variabele zelfs meerdere stackspaces doorlopen tijdens z'n lifetime.

C#:
1
2
3
4
5
6
7
8
void test()
{
    int a = eenBerekening();
    doeIets(a);

    int b = andereBerekening();
    doeIets(b);
}

a en b kunnen hier dezelfde stackspace innemen, omdat je niet meer van a leest voor je b schrijft.

C#:
1
2
3
4
5
6
7
8
9
10
11
void test()
{
    int a = eenBerekening();
    doeIets(a);

    int b = andereBerekening();
    doeIets(b);

    a = nogEenAndereBerekening();
    doeIets(a);
}

De tweede a hoeft niet op dezelfde plek als de eerste a te staan - het is in feite een andere variabele met dezelfde naam.

(Natuurlijk breekt dit op het moment dat je unsafe code gaat schrijven en het adres neemt van een variabele)

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


Acties:
  • 0 Henk 'm!

  • Vedett.
  • Registratie: November 2005
  • Laatst online: 18:29
HawVer schreef op woensdag 23 januari 2008 @ 22:23:
Ik dacht ik ga eens wat testen draaien en dan door middel van ildasm de code omzetten naar msil. Tijdens het compileren wordt c# code omgezet naar msil code welke weer vertaald wordt naar systeem specifieke code dmv jit compiler. Ildasm draait dit proces om en genereert van dll's msil code.
Ik denk dat je het goed bedoelt, maar verkeerd schrijft. ILDasm doet helemaal niets! Het is puur weergeven van MSIL code in de DLL. De DLL bevat die MSIL code al dus er moet helemaal niets gegenereerd worden.

Ik vermoed dat je reflector bedoelt.

Ik heb ILDasm ook even boven gehaald met volgende code:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
        public static void BeforeLoopDeclaration()
        {
            int i;
            object var; 
            for(i=0; i < 10; i++) 
            { 
                var = new object(); 
                //doe wat met var 
            }
        }
        
        public static void InLoopDeclaration()
        {
            //en 
            int i;
            for(i=0; i < 10; i++) 
            { 
                object var = new object(); 
                //doe wat met var 
            }
        }

De integer "i" heb ik als eerste gedeclareerd, omdat anders de waarden op de stack nog verwisseld zijn. Nu geeft dit dus perfect dezelfde MSIL Code. Buiten de naam van de methode uiteraard. Er is dus ook helemaal geen verschil mogelijk in optimalisatie door de JIT-Compiler.
Pagina: 1