Skrev ett litet bloginlägg om användandet av variabler. Jag vet inte! Du kan ha rätt i sak men samtidigt tycker jag att det är ganska skönt att ha variabler samlade i grupper så man lättöverskådligt kan se allt i scoopet på en gång. Ctrl + F finns ju istället som alternativ till scrollen. Jag tror det är en fråga med samma svar som vad som är bäst mellan SAAB och Volvo. >Jag tror det är en fråga med samma svar som vad som är bäst mellan SAAB och Volvo. <b>Variables värde kommer finnas i minnet under längre tid.</b> Per: Jag hade uppfattningen om att man som best practise endast reserverar minne för variabler i början på en funktion. Jag menar snarare på det att om en kod är så lång att det är problematiskt att veta var, när eller till vad en variabel används, så ligger problemet inte på att variabeln är deklarerad i toppen utan att funktionen är dumt skriven och/eller att man har använt en dålig namngivningskonvention. Niklas: OBS!Flytande/Flygande Variabler...
Isäller för att göra en krönika här eller Artikel valde jag att blogga så här är länken för den som är nyfiken.
OBS! på Engelska.
http://www.nsquared2.net/johan/viewpost.aspx?PostID=160&showfeedback=true
//JohanSv: Flytande/Flygande Variabler...
Sv:Flytande/Flygande Variabler...
Intresant jämförelse. Men SAAB är väl bättre än Volvo ;)
Det finns tre skäl till att inte deklarera variablar i en grupp längst upp i koden och det mesta handlar om att sparar tid för debugging.
* Variablen har alridg blivit satt till ett värde. Variables värde kommer finnas i minnet under längre tid.
* Variablen värde är gammalt. Variablen har fått sitt värde någonstans men är inte längre giltligt.
* Svårt att veta vad varablen är tillför.
Om du skriver kod som tex är på 1000 rader kod och deklarerar variablar i toppen, men använder först en av dom på rad 990. Så kommer den variablen leva genom hela scopet från där den intitierades fram till rad 990+(där den inte används längre). Om du i dessa 1000 rader kod har for lopar eller andra operationer som ev kan ta lite tid att utföra, så lever din variabel onödigt länge i minnet. Ett annat probelm är att när du befinner dig på rad 990 där du först använder variablen, så vet du inte va den har för värde eller får sitt värde i från (om värdet sätts tex på rad 200) etc (Ut gå från att det inte är du som skrivit koden, men ska fixa en bug på rad 992 åt någon annan).
Tex:
Kod 1.
Rad
1 Dim total As Double
2 Dim accountIndex As Integer
3 accountIndex = 1
4 total = 0
...
200 total = GetTotal(accountIndex)
...
990 if total > 100 then
I koden ovan, så om du står på rad 990, så vet du inte vad total har för värde, eller vart den har sist fått sitt värde ifrån. För att ta reda på det så måste du scrolla upp i koden för att leta (tex med CTRL+ F för att snabbt hitta med söken). Om du koden skulle skrivas på följande sätt:
Kod 2.
Rad
985 Dim accountIndex As Integer
986 accountIndex = 1
987
988 Dim total As Double
989 total = GetTotal(accountIndex)
990 if total > 100 then
I detta exampel jämfört med det tidigare, så ser du vart variablarna initieras och får sina värden. Detta leder till att det blir mkt enklare att förstå koden etc.
Det första exemplet ovan, föklaras som "coding horror" och ska helst undvikas. inte för din egen skull utan även för andra som ska in i koden efter dig.
En bra initializering har följande design:
Dim accountIndex As Integer
//Kod som använder accountIndex ska finnas här
...
Om vi nu tar och tittar på variabelns livstid så i kod 1 lever variablen accountIndex från rad 3 fram till rad 200. Total lever från rad 4 fram till rad 990. Mellan rad 4 och 990 så kan det före komma operationer som kan ta olika lång tid att utföra, vilket gör att variabeln lever längre än nödvändigt i minnet. Se på följande exempel:
Kod 3.
1 'Initiera alla variabler
2 recordIndex = 0
4 done = false
...
26 do while recordIndex < recordCount
27 ...
28 recordIndex = recordIndex + 1
...
64 do while Not done
...
69 if total > projectedTotal then
70 done = true
I koden ovan så ser du att recordIndex lever fram tills rad 28. total lever fram till rad 69 och done till 70.
När en variable inte används längre så kommer den placeras i GC (Garbage Collection). Men hjälp av lite mattematik så kan vi räkna ut variablarnas livslängd:
recordIndex (rad 28 - rad 2 + 1) = 27
total (rad 69 - rad 3 + 1 ) = 67
done (rad 70 - rad 4 + 1 ) = 67
Medel (27 + 67 + 67)/3 = 54
Denna levnadstid kan minnimeras genom att koden i kod 3 skrivs på följande sätt:
Kod 4.
25 recordIndex = 0
26 do while recordIndex < recordCount
27 ...
28 recordIndex = recordIndex + 1
...
62 total = 0
63 done = false
64 do while Not done
...
69 if total > projectedTotal then
70 done = true
Här är livslängden på variablarna i kod 4:
recordIndex (rad 28 - rad 25 + 1) = 4
total (rad 69 - rad 62 + 1 ) = 8
done (rad 70 - rad 63 + 1 ) = 8
Medel (4 + 8 + 8)/3 = 7
Nu var inte min tanke att skriva så långt inlägg som jag nu gjorde, men så belv det. Johan har säkert nämnt mycket om det här i hans artikel så nu blev det säkert en repetition. Men om nu kod 3 var Volvo och Kod 4 var SAAB, då skulle jag valt SAAB ;)Sv: Flytande/Flygande Variabler...
Talar du om något särskilt språk nu? Ofta reserveras utrymme på stacken ändå i början av funktionen/metoden oavsett var variablerna ligger.Sv:Flytande/Flygande Variabler...
Lite luddigt formulerat kanske, men CLR:en är rätt smart och kan uppfatta om ett objekt inte används längre, och på så sätt kan den tidigare läggas i GC:en. Om du tex i rad 1 initierar ett objekt och tilldelar den ett värde, så om du sedan i rad 1000 sätter den tex till null så läggs inte objektet i GC:en fören på rad 1000, för den märker att objektet används senare. Hoppas det gav en bättre bild ;)Sv:Flytande/Flygande Variabler...
ex: dim x as mytype
Men på detta sätt endast reserverar minne (inte använder), och den reservationen släpps när variabeln tappar alla referenser. den assignas väl inte förrns man exempelvis kör: x = new mytype
Och att detta är bra för överskådlighet, debug, etc. (saab / volvo? ) :)
Dessutom om man inte använder variablen behöver man heller inte close'a eller dispos'a den, om den bara är reserverad.
Men om man kör: dim x as mytyp = new mytyp
Så både reserveras och assignas minnet med en instans av mytyp. Man bör dispos'a den.
Använder man:
dim x as NEW mytype
Så reserveras minne, och assignas inte förräns vid första åtkomst av objektet "x". (den late mannens tillvägagångssätt)
OBS! Jag hävdar ingenting, vet mycket väl att ni som programmerat ett tag har större koll, detta är bara min tolkning av läsning så rätta mig mer än gärna, och dessutom var det på vb6 tiden så det är mycket möjligt helt fel! :)
//RickardSv: Flytande/Flygande Variabler...
Naturligtvis kan man tänka sig att ha loopspecifika variabler som verkligen är specifikt bundna till en viss del av en funktion, etc., men det är ju enstaka detaljer.Sv:Flytande/Flygande Variabler...
Det kan finnas metoder som är korta men har operationer som tar lång tid att uföra, i de fallen kan det tex vara onödigt att låta ett objekt ligga i minnet om den inte ska användas fören efter operationen etc.
OBS! Detta va bara ett exempel.
Att initiera alla variabler i toppen av en metod är vad Steve McConnel kallar för coding horror och jag håller med honom. Visst kan det ev se bättre ut att lägga alla variabler på ett och samma ställe genom att gruppera dom i toppen av en metod, för då har man dom samlade. Det kan dock ställa till med problem, även om det kanske är sällan (om man inte skriver långa metoder). Även om det är sällan det händer, så är det alltid bra att förebygga alla möjliga tänkbara fel genom att använda en bra programmerings layout.Sv: Flytande/Flygande Variabler...
Detta gäller då inte constanter som ersätare för ex Magic numbers eller magic text.
Mvh Johan