Det første dataprogrammet jeg noensinne skrev så slik ut:
10 PRINT "Magnar er kul"
20 GOTO 10
Det var veldig kult. Åpenbart.
GOTO
er den ultimate friheten innen programflyt. Man kan flytte eksekveringen
til hvor som helst i koden. Dritbra greier da!
Ikke sant?
Du gikk ikke på den, nei. I dag er vi naturligvis enige alle sammen om at GOTO
er en uting. Det startet da Dijkstra populariserte uttrykket “considered
harmful” på slutten av 60-tallet.
Jeg kunne kanskje allerede her klappet meg selv på skulderen. Spørsmålet i tittelen er allerede besvart. Men jeg skal skrive litt til.
¶En artig øvelse du har gjort før
Her skal du få en kodesnutt som du har sett 100 ganger:
var result = [];
for (var i = 0, l = items.length; i < l; i++) {
var item = items[i];
result.push(transform(item));
}
Hva gjør den? Ta en ekstra titt gjennom og se.
Svaret er at den samler sammen resultatet av å kalle funksjonen transform
på
alle elementer i items
. Det er det vi pleier å kalle map.
En ny snutt:
var result = [];
for (var i = 0, l = items.length; i < l; i++) {
var item = items[i];
if (check(item)) {
result.push(item);
}
}
Hva gjør denne da? Er du sikker?
Joda, du hadde nok rett. Svaret er at den finner alle elementer i items
som
består sjekken i check
, og samler dem i en ny liste. Det er altså filter
(eller select).
La oss avslutte denne artige øvelsen med noen flere kodesnutter. Se om du klarer å se hva de gjør.
var result = [];
for (var i = 0, l = items.length; i < l; i++) {
var item = items[i];
if (check(item)) {
result.push(transform(item));
}
}
var result = [];
for (var i = 0, l = items.length; i < l; i++) {
var item = transform(items[i]);
if (check(item)) {
result.push(item);
}
}
var result = [];
for (var i = 0, l = items.length; i < l; i++) {
var item = items[i];
if (check(transform(item))) {
result.push(item);
}
}
¶Det er ikke bare GOTO som er harmful
Gjorde det der litt vondt? Kanskje du ikke gadd engang?
Hvorfor var det vondt? Kan det ha noe å gjøre med at kodesnuttene var veldig like, men gjorde veldig forskjellige ting? Eller at du måtte gjenskape loopen mentalt for å pusle sammen intensjonen bak koden?
Hadde det vært greiere å parse disse?
var result = items.map(transform);
var result = items.filter(check);
var result = items.filter(check).map(transform);
var result = items.map(transform).filter(check);
var result = items.filter(i => check(transform(i));
Husker du at jeg spurte deg “Er du sikker?” Da måtte du nesten gå tilbake til
for-loopen og sjekke. Hadde du gått glipp av en detalj? Hadde jeg vært snedig
med min termineringsklausul? Eller den der ++
-en?
Hva om jeg spør deg om items.map(transform)
… er du sikker?
Såklart du er sikker.
¶for gir oss for mye frihet
Frihet til å rote det til. Frihet til å gjemme snedige detaljer. Og ikke minst:
Frihet til å bygge ut loopen. Legge på litt mer greier. En ekstra sjekk. En
ekstra transformasjon. += 2
istedet for ++
.
Og hver gang du snubler over en for
så må du sjekke. Hvilke detaljer er det
her? Har jeg stirret lenge nok på denne koden til å være sikker på hva den gjør?
Det koster dyrt.