De herkomst van if-then-else

If-then-else is de manier waarop we in programmeertalen over condities praten: als iets waar is, doe dan dit, en anders (else) doe je iets anders. Dat klinkt als gewoon Engels, toch? Dat is het echter niet. In normale spreektaal kan ik "else" niet gebruiken als voegwoord; dat kan alleen in computerprogramma's.

Waar komt dit "else" vandaan? Het is een mysterie. Het is een detail dat te microscopisch is om het te hebben gehaald in boeken over de geschiedenis van programmeertalen. Het lijkt niet voort te komen uit enquêtes, juridische procedures of algoritmen zoals die vóór de komst van computers werden geschreven. Je vindt wel "if yes" (indien ja), "if no" (indien nee) en "if however" (indien echter), maar geen "else".

De vroege computers en conditionele sprongen

De eerste computer die in staat was om verschillende instructies uit te voeren afhankelijk van het resultaat van een vorige berekening, was naar alle waarschijnlijkheid de Eniac. In 1946 schreven Haskell Curry en Willa Wyatt een rapport over een programma om een functie om te keren. Zij gebruikten de term "discriminatie" voor de mogelijkheid om een beslissing te nemen op basis van welk van de twee getallen groter was.

De Eniac had echter geen instructie die "discriminate" heette. De machine werd geprogrammeerd met draden en draaiknoppen op plugborden. Het controlepaneel voor de instructie die de berekening voor een beslissing maakte, was via fysieke draden verbonden met de instructies die daarop konden volgen.

Al snel kregen computers voldoende geheugen om programma's in het geheugen op te slaan in plaats van ze fysiek aan elkaar te verbinden. In plaats van een fysieke reeks instructies was er nu een numerieke reeks. Enkele speciale instructies konden de computer dwingen om naar een ander punt in de reeks te springen.

Een voorbeeld hiervan is de conditional jump (conditionele sprong) instructie van een van de eerste commercieel geproduceerde computers. Deze controleerde of het laatst berekende getal negatief was. Zo ja, dan werd de besturingsstroom omgeleid naar een specifieke locatie in het geheugen; zo nee, dan ging de besturing door naar de volgende instructie.

Dit was bedoeld voor een specifiek gebruikspatroon: als je een taak bijvoorbeeld 10 keer wilde uitvoeren, telde het programma hoe vaak het dit al had gedaan en trok er vervolgens 10 vanaf. Als het resultaat negatief was, was de taak nog niet voltooid en sprong het programma terug om nog een ronde te doen.

De evolutie naar hogere programmeertalen

Dit idee werd overgenomen in de eerste programmeertalen van een hoger niveau, zoals de taal van Halcombe Laning en Neal Zierler voor de Whirlwind-computer. Hun conditionele sprong werkte op dezelfde manier, behalve dat de genummerde stappen van het programma algebraïsche expressies waren in plaats van enkele machine-instructies.

Fortran, de eerste populaire programmeertaal, generaliseerde dit idee door sprongen naar drie locaties tegelijk te definiëren, afhankelijk van of een berekening negatief, nul of positief was. Fortran gaf dit het naam "if". Deze drievoudige "if" was krachtiger dan alleen controleren op een negatief getal, maar was waarschijnlijk ook verwarrender. Elke beslissing betekende namelijk een discontinuïteit in de besturingsstroom, in plaats van dat programmeurs alleen hoefden na te denken over het normale scenario (dat doorliep) en het ongebruikelijke scenario (dat sprong).

Flow-Matic, de voorloper van COBOL ontwikkeld door Grace Murray Hopper, maakte de drievoudige "if" iets begrijpelijker door te spreken over het vergelijken van twee getallen in plaats van over de tekens van getallen. Zij introduceerde de naam "otherwise" voor het geval waarin de vergelijking niet was wat je zocht.

De ontwikkeling van ALGOL en de geboorte van "else"

In 1958 startten twee computerorganisaties uit respectievelijk Amerika en Duitsland een gezamenlijk project om een standaard, machine-onafhankelijke taal te ontwikkelen. Een taal die natuurlijk zou zijn voor mensen om te bespreken, in plaats van natuurlijk om te implementeren op een specifieke machine. Beide groepen brachten een conceptvoorstel naar de gezamenlijke conferentie.

De Duitse auteurs maakten twee grote conceptuele sprongen in hun formulering van de "if"-instructie:

  1. Ze lieten de conditie bepalen door elke willekeurige booleaanse expressie, in plaats van prioriteit te geven aan de vorm "kleiner dan/gelijk aan/groter dan".
  2. In plaats van een abrupte sprong in de besturingsstroom, zorgde hun "if"-instructie er alleen voor dat de stroom tijdelijk werd omgeleid. Aan het einde van de conditie — of deze nu waar of onwaar was — zou het programma hervatten bij de "always"-instructie aan het einde van het blok. Het enige verschil was of de tussenliggende instructies waren uitgevoerd.

In het Duitse voorstel verscheen iets dat leek op "else" in een tweede, geheel andere conditionele vorm genaamd "case". In tegenstelling tot de "case" zoals we die nu kennen, was hun versie een andere manier om booleaanse condities te schrijven, waarbij de condities in een apart blok stonden van de instructies die ze aanstuurden. Waarschijnlijk dachten zij dat deze vorm gemakkelijker was voor complexere vergelijkingen.

Hier verscheen voor het eerst het woord "else", voor het geval waarin geen van de andere gevallen van toepassing was. Waarom ze het "else" noemden, wordt niet vermeld. Wel staat er dat dit document oorspronkelijk in het Duits was geschreven en haastig naar het Engels was vertaald. Ik vermoed dat een zorgvuldig gekozen Duits woord waarschijnlijk werd vertaald als een archaïsch Engels woord en daarna nooit meer is aangepast. Helaas hebben we de originele Duitse tekst niet om dit te verifiëren.

Het Amerikaanse voorstel had ook het idee om instructies aan te sturen via booleaanse expressies, maar het had geen "if"-trefwoord. In plaats daarvan stuurde een expressie, gevolgd door een pijl, de daaropvolgende instructies aan. In tegenstelling tot het Duitse blok met "ifs", zorgde de Amerikaanse vorm ervoor dat als één expressie in een blok als "waar" werd geëvalueerd, de volgende expressies werden overgeslagen (short-circuiting), zoals "else if" dat nu doet.

De weg naar de standaard: Algol 60 en LISP

De twee organisaties voegden hun voorstellen samen in één document genaamd de International Algebraic Language, wat kort daarna werd omgedoopt tot Algol. De "if"-instructie in dit gecombineerde document leek veel op het Duitse voorstel, maar elimineerde de "always"-instructie. Elke "if" stond nu op zichzelf; wilde je meerdere instructies door dezelfde expressie laten aansturen, dan kon je "begin" en "end" gebruiken om ze te groeperen. Er was in deze formulering van "if" niets dat leek op "else".

Algol 58 had echter ook een tweede conditionele vorm, genaamd "if either". Hierin kon je "or if" gebruiken om hetzelfde te bereiken als we nu doen met "else if". Maar er was niets dat gelijkstond aan "else" op zichzelf, zonder een aanvullende "if".

Het jaar daarop werd het verhaal complexer. John Backus, die eerder het Fortran-project had geleid, introduceerde het idee van formele grammatica's voor programmeertalen. In zijn beschrijving van Algol ontbrak de "if either"-vorm. In plaats daarvan was er een trefwoord genaamd "converge", waardoor de top-level "ifs" in een blok zich gedroegen als "else ifs".

Ondertussen had John McCarthy van MIT in 1957 een voorstel geschreven voor LISP. Hij introduceerde het idee van de conditionele expressie, in tegenstelling tot de conditionele instructie. Het belangrijke verschil is dat een expressie altijd een waarde moet hebben, terwijl een instructie simpelweg niet wordt uitgevoerd als de conditie onwaar is. Daarom eindigde zijn "if-functie" altijd met een clausule genaamd "otherwise", die de waarde van de expressie gaf wanneer geen van de andere condities waar was.

De conditionele expressies van McCarthy inspireerden Klaus Samelson om aan het eind van 1959 de twee separate conditionele modellen van Algol op te schonen en te verenigen. Hij elimineerde de volledige "if either"-vorm en behield alleen de eenvoudige "if", maar voegde een clausule toe genaamd "else" die werd uitgevoerd wanneer de expressie die de bijbehorende "if" aanstuurde onwaar was. Je kon condities aan elkaar ketenen met "else if", maar je kon "else" ook alleen gebruiken voor een laatste set instructies die zouden draaien als geen van de condities waar was.

"If-then-else" was de enige conditionele vorm die het volgende jaar in het Algol 60-rapport verscheen, en het is de vorm die bijna alle daaropvolgende programmeertalen hebben gevolgd.

Weerstand en alternatieven

Hoewel het nu vanzelfsprekend lijkt, was het voor mensen in 1960 lastig om over na te denken. Het rapport besteedt anderhalf pagina aan de uitleg van de werking.

Zoals ik al noemde, klinkt het gebruik van "else" als voegwoord vreemd. Christopher Strachey's CPL-taal (de grootouder van C en daarmee de voorouder van de meeste huidige talen) weigerde "else" te gebruiken en noemde het "onwetend incorrect Engels". Hij vond dat we "test … then … or" zouden moeten schrijven, wat echter ook niet erg natuurlijk klonk en niet is aangeslagen.

Ook de MAD-programmeertaal sloeg een andere weg in. MAD stond bekend om zijn extreem lange trefwoorden. Naast het gebruik van "whenever" in plaats van "if", gebruikte het "otherwise" in plaats van "else" en "or whenever" in plaats van "else if". Opvallend in de MAD-handleiding is de inspringing (indentatie) in de voorbeelden; het duurde jaren voordat andere talen deze stijl van inspringen voor condities overnamen, hoewel het nu ondenkbaar is om het anders te doen.

Maar zelfs terwijl CPL en MAD het woord "else" meeden, behielden ze de structuur en veranderden ze enkel het vocabulaire. Taalontwerpers zoeken nog steeds naar de perfecte manier om een for-loop te schrijven, maar de zoektocht naar de perfecte conditionele vorm lijkt in 1959 beëindigd te zijn.

Dank aan Klaus Samelson voor het geven van een instrument om mee te denken en een woord om over te puzzelen.