Imperatief programmeren
Imperatief programmeren (ook wel procedureel programmeren genoemd) is een programmeerconcept uit de informatica waarbij programma's opgesteld worden in de vorm van opdrachten die direct uitgevoerd kunnen worden. Het tegenovergestelde van imperatief programmeren is declaratief programmeren, dat niet iets doet maar iets beschrijft.
Vaak wordt imperatief programmeren ook naast object-georiënteerd programmeren gelegd. Een taal waarmee alleen geprogrammeerd kan worden met klassen en hun bijbehorende memberfuncties, zoals Java (elke functie moet hier een member zijn van een klasse), wordt dan een zuiver object-georiënteerde programmeertaal genoemd. Hiernaast ligt de zuiver imperatieve taal, bijvoorbeeld C, om alleen losstaande functies te plaatsen. Als laatste zijn er nog hybride talen zoals C++ en PHP, waarmee men zowel object-georiënteerd als imperatief kan programmeren.
Berekeningsmodellen
bewerkenAls een computer een programma uit moet voeren, dan doet de computer dat door achtereenvolgens de instructies uit te voeren die het programma voorschrijft. Dit werkt doordat beide (computer en programma) opgesteld zijn volgens hetzelfde concept van programmaverwerking – zij "denken" beide hetzelfde over hoe het programma uitgevoerd dient te worden.
In dit concept van uitvoering zijn twee termen belangrijk: de turingmachine en de Von Neumann-cyclus.
Turingmachine en berekenbaarheid
bewerkenDe turingmachine is een model van berekenen: de turingmachine beschrijft in detail hoe een berekening uitgevoerd dient te worden. Met dit model in de hand wordt het mogelijk om na te gaan denken over zaken als
- Wat kan er precies berekend worden?
- Hoe moeilijk is het om iets te berekenen?
Het turingmodel van berekenbaarheid bestaat uit twee onderdelen: een (oneindig) geheugen en een toestandsautomaat.
Geheugen
bewerkenHet geheugen dient om alle relevante informatie over de berekening bij te houden: in het geheugen ligt opgeslagen wat er al gebeurd is en wat de uitkomsten waren, wat er nog behandeld dient te worden en in welke volgorde, en belangrijkst van alles: waar de berekening nu ("op dit moment") is, in welk stadium. Dit laatste wordt de toestand van de machine genoemd.
Toestandsautomaat
bewerkenDe toestandsautomaat voert de eigenlijke berekening uit, in kleine stapjes. De automaat bestaat in feite uit één grote serie beschrijvingen van de vorm "in deze toestand moet je deze stap zetten". Een hele berekening van de turingmachine is dan een aaneenschakeling van veel van deze kleine stappen.
Von Neumann-cyclus en hardware
bewerkenDe Von Neumann-cyclus beschrijft hoe een computer in praktische zin zou kunnen werken, in termen van het ophalen en uitvoeren van één enkele instructie en dan doorgaan met de volgende instructie. Dit is de centrale gedachte achter de werking van vrijwel iedere, moderne computer.
Het imperatieve programma
bewerkenHet imperatieve programma is een programma dat een berekening beschrijft volgens het turingmodel: de gehele berekening valt uit elkaar in een lange serie kleine stappen die ieder op zich de toestand van de berekening een beetje aanpassen, totdat er uiteindelijk een compleet antwoord "uit komt rollen".
Het imperatieve programma doet dit door gebruik te maken van de architectuur van de onderliggende machine: het geheugen van de computer vormt het geheugen waarin de berekening en de toestand opgeslagen liggen, de processor wordt de toestandsautomaat. Iedere stap van de automaat past precies in één omloop van de Von Neumann-cyclus en heeft de vorm "beschouw de huidige toestand en mogelijke stappen om te zetten (instructie-fetch); beslis wat er nu precies moet gebeuren (instructie-decode); pas dat toe op de huidige toestand (instructie-execute); begin opnieuw".
Beschouwt men de code van een imperatief programma (dat zo genoemd wordt omdat het bestaat uit een serie opdrachten of bevelen), dan kan men deze structuur direct terugzien, bijvoorbeeld in het volgende stukje code in de programmeertaal C:
- ....
- c = 12 + 13;
- d = c;
- c++;
- ....
- printf("Hello, World!");
Dit zijn allemaal kleine opdrachten (simpele stappen) die door de onderliggende machine in volgorde uitgevoerd dienen te worden. Bovendien maken zij direct gebruik van de verdeling van het geheugen in kleine cellen – dat wil zeggen, zowel van het geheugenmodel van de turingmachine als van de fysieke eigenschappen van de hardware in de computer – door deze cellen direct aan te spreken in termen van variabelen in het programma.
Onderscheid met andere soorten programmeertalen
bewerkenImperatieve talen zijn in hun vorm sterk verbonden aan het berekeningsmodel van Turing en de onderliggende hardware. Hierin onderscheiden zij zich van functionele programmeertalen, die het Churchmodel van functietoepassing gebruiken als model van berekening (zie ook Lambdacalculus). Ook onderscheiden de imperatieve talen zich van de logische programmeertalen, waarin het bewijsobject en de predicatencalculus als berekeningsmodel centraal staan.
De logische en functionele talen, die in vorm sterk afwijken van de imperatieve talen, worden declaratieve programmeertalen genoemd.
Ten slotte is er veel onenigheid over de positie van objectgeoriënteerde programmeertalen in dit geheel; deze talen verdelen een berekening in verschillende onderdelen, waarbij ieder onderdeel de verantwoordelijkheid is van een opzichzelfstaand programmaobject. Deze objecten op zich worden intern echter weer opgesteld aan de hand van één (of meer) van de bovengenoemde modellen, dus de vraag blijft of dit model als iets geheel afzonderlijks gezien kan worden.
Elementen van imperatieve programmeertalen
bewerkenIn de meeste talen worden sleutelwoorden (of keywords) gebruikt om opdrachten aan te geven. Deze woorden zijn eigenlijk altijd uit het Engels afkomstig. Ook in andere landen gebruikt een programmeur de Engelstalige sleutelwoorden. Veel programmeertalen komen niet alleen qua programmeerparadigma overeen, maar ook gedeeltelijk qua syntaxis en sleutelwoorden, zodat de kenner van een programmeertaal weinig moeite zal hebben met het leren van een verwante taal.
Enkele definities
bewerken- Een identifier is een door de gebruiker gekozen woord. Identifiers worden vooral gebruikt voor variabelen waaraan een waarde kan worden toegekend. Een identifier bestaat uit een aantal letters en cijfers, te beginnen met een letter. In Cobol mag een identifier met een cijfer beginnen maar moet er minstens een letter in voorkomen.
- Een expressie is een waarde die kan worden uitgerekend. Een eenvoudig getal is een expressie, maar
3+(5*A)
ook. De schrijfwijze van expressies is in de meeste talen gelijk. - Een array is een aantal variabelen die samen een identifier hebben. Om een enkel element van een array te adresseren, moet een index worden opgegeven. De syntaxis is
arraynaam(index)
ofarraynaam[index]
. Bij BCPL wordt een uitroepteken gebruikt:arraynaam!index
. Een array kan ook meerdere indices hebben, in dat geval worden die gescheiden door komma's:arraynaam[index1,index2]
(bij APL door puntkomma's, bij C is de schrijfwijzearraynaam[index1][index2]
).
Getal
bewerkenGetallen worden op de gebruikelijke wijze geschreven. Het decimaalteken is een punt. Er is geen scheidingsteken tussen duizendtallen.
Zeer grote en kleine getallen kunnen worden aangegeven met een macht van tien, zoals gebruikelijk in de wetenschap, en daarvoor wordt meestal de letter E gebruikt. Dus het getal 6,022 × 1023 wordt geschreven als 6.022E23
.
In sommige talen kan men een ander talstelsel kiezen. Bij ieder getal moet worden aangegeven welk talstelsel wordt gebruikt (dat verschilt per taal). Een hexadecimaal getal kan, afhankelijk van de taal, worden genoteerd als 0Xabcd
of als 0abcdH
. Let op de voorafgaande nul, een getal moet altijd met een cijfer beginnen (wat met een letter begint is immers een identifier). In C begint een octaal getal met een nul, dus 15
is decimaal en 013
is octaal.
String
bewerkenEen string is een reeks tekens die afgedrukt kan worden. Een string staat meestal tussen aanhalingstekens. Daaruit volgt dat het niet goed mogelijk is aanhalingstekens in een string op te nemen. De gebruikelijke oplossing daarvoor is dat men twee aanhalingstekens achter elkaar zet. In sommige talen geldt een string als eenheid, in andere is het een array van tekens, die dus geïndiceerd kan worden.
Blok
bewerkenIn moderne talen is het nodig statements te groeperen. Zo'n groep statements heet een blok of samengesteld statement en geldt zelf weer als een enkel statement. Het groeperen geschiedt met BEGIN
en END
. Andere talen gebruiken hiervoor geen woorden maar bijvoorbeeld {
en }
.
CALL
bewerkenBij een aanroep (call) van een subroutine (ook wel procedure, functie of methode genoemd) wordt de naam van de subroutine gegeven, gevolgd door (meestal tussen haakjes) de parameters (ook wel argumenten genoemd). Zijn er geen parameters, dan zijn vaak wel de haakjes nodig.
In sommige talen wordt een expliciet gereserveerd woord CALL
voorgevoegd.
- In COBOL schrijft men
PERFORM sectie- of paragraafnaam THRU sectie- of paragraafnaam
. Het woordjeTHRU
betekent tot en met en de uitvoering eindigt dan ook bij de eerste sectie of paragraaf ná de genoemde naam.
Imperatieve elementen
bewerkenBij imperatief programmeren is een programma een samenstel van instructies die de computer moet uitvoeren, waarbij aan geheugenlocaties of meer abstracte variabelen waarden worden toegewezen en uitgelezen. Zulke instructies worden samengesteld tot programma's met behulp van elementen die de control flow specificeren. De meeste programmeertalen veronderstellen of ondersteunen deze manier van werken; typische elementen in zulke talen zijn de volgende.
Toewijzing
bewerkenIn een toewijzing (assignment) krijgt een variabele een waarde. De schrijfwijze is meestal:
variabele=expressie
variabele:=expressie
- Bij sommige talen (o.a. C en APL) kan een assignment ook midden in een expressie voorkomen.
- Bij COBOL zijn er andere mogelijkheden. Wordt er niets berekend, dan schrijft men
MOVE waarde TO variabele
. Een eenvoudige berekening kan worden geschreven alsADD waarde TO variabele
, met daarachter eventueelGIVING variabele
. De meest algemene assignment luidtCOMPUTE variabele = expressie
. - Bij sommige implementaties van BASIC wordt de assignment voorafgegaan door het woordje
LET
.
IF
bewerkenNa IF
komen een voorwaarde en een statement dat voorwaardelijk uitgevoerd moet worden. Tussen de voorwaarde en het statement komt het woord THEN
(ook weleens DO
). Na de voorwaardelijk uit te voeren statements komt eventueel ELSE
gevolgd door een statement dat juist wordt uitgevoerd als niet aan de voorwaarde is voldaan.
- Bij Fortran schrijft men
IF (
expressie) label1, label2, label3
. Afhankelijk van de waarde van de expressie gaat de uitvoering van het programma verder bij een van de labels. - Bij sommige implementaties van BASIC schrijft men
IF expressie THEN regelnummer
. Is aan de voorwaarde voldaan, dan gaat de uitvoering bij het opgegeven regelnummer verder. Let op het ontbreken vanGOTO
. - In BCPL bestaan drie varianten, waarbij
ELSE
alleen in de derde variant mag voorkomen:IF
conditieTHEN
statement1UNLESS
conditieTHEN
statement2TEST
conditieTHEN
statement1ELSE
statement2
SWITCH of CASE
bewerkenEen IF-statement heeft twee takken, de THEN
-tak en de eventuele ELSE
-tak. Is er een gecompliceerde keuze nodig, dan kan men vaak gebruikmaken van een SWITCH
-statement (in andere talen CASE
). Er wordt een expressie genoemd en die wordt vergeleken met een aantal constanten om te bepalen welke tak moet worden uitgevoerd.
FOR of DO
bewerkenNa FOR
(ook wel DO
) komt een statement dat herhaaldelijk uitgevoerd moet worden (een iteratie). Er wordt een lopende variabele gegeven, met begin- en eindwaarde en stapgrootte. Deze constructie wordt meestal gebruikt voor herhalingen waarvan het aantal tot een vooraf bepaalde grens is beperkt.
- In Fortran:
DO label variabele=beginwaarde, eindwaarde, stapgrootte
. In tegenstelling tot bij modernere talen kan hierna een onbeperkt aantal statements volgen, het label wijst naar het laatste statement van de iteratie. (Bij moderne talen moeten de statements tot een enkel statement samengevoegd zijn, zie Blok.) - In PL/1:
DO variabele=beginwaarde TO eindwaarde BY stapgrootte
- In Algol:
for variabele:=beginwaarde to eindwaarde step stapgrootte do
- In C:
for (beginassignment; testconditie; verhogingsexpressie)
FOR EACH
bewerkenfor each
. Geeft een iteratie, een lopende variabele en een enumeratie, dat wil zeggen, een object dat zelf al een standaardmethode definieert op iteratie over de waarden ervan mogelijk te maken. Het kan gaan om een al bepaalde collectie waarden (zoals een lijst of array), maar dat hoeft niet.
Het belangrijke verschil met FOR is dat er geen volgnummer wordt gebruikt om de elementen af te lopen.
WHILE
bewerkenWHILE
. Ook dit is een iteratie, maar in plaats van een lopende variabele wordt een voorwaarde gegeven; de iteratie wordt uitgevoerd totdat niet meer aan de voorwaarde voldaan is. Dit wordt meestal gebruikt voor iteraties waarvan het aantal stappen op het moment van ingaan nog onbekend is.
- Bij sommige talen kan
FOR
metWHILE
gecombineerd worden, bijvoorbeeld in Algol:for variabele=beginwaarde to eindwaarde step stapgrootte while conditie do
. De iteratie stopt als de eindwaarde bereikt is of als de conditie onwaar is geworden. - BCPL kent ook
UNTIL
.
BREAK
bewerkenOm een iteratie voortijdig te beëindigen, bestaan er statements als BREAK
of EXIT
. Om direct verder te gaan met de volgende iteratie, schrijft men LOOP
of CONTINUE
. Om de uitvoering van een subroutine te beëindigen, schrijft men RETURN
.
- In Fortran is
CONTINUE
een dummystatement dat geen effect heeft. Het wordt vaak gebruikt om een label te plaatsen.
Label
bewerkenEen label is een identifier waarmee een punt van het programma gemarkeerd wordt. Meestal wordt een label gebruikt in een GOTO
-statement. Na een label komt meestal een dubbele punt.
- In Fortran is een label een getal dat in de eerste zes posities van een regel wordt geplaatst. (De programmacode begint bij Fortran in positie 8.) De regels hoeven niet genummerd te zijn en de nummers hoeven ook niet op volgorde te zijn.
- BASIC heeft geen labels maar regelnummers. Elke regel moet genummerd zijn.
- COBOL kent geen labels maar paragrafen en secties. Een enkele identifier, te beginnen in positie 8, is een paragraafnaam en de paragraaf eindigt bij het begin van de volgende paragraaf of het einde van de sectie. Een identifier gevolgd door het woord
SECTION
is een sectienaam en de sectie eindigt bij het begin van de volgende sectie.
GOTO
bewerkenNa GOTO
of GO TO
komt een label. De uitvoering van het programma gaat op de plek van het label verder. Bijna alle programmeertalen kennen GOTO
, maar het gebruik ervan wordt in de moderne programmeerpraktijk afgeraden omdat het gemakkelijk aanleiding geeft tot het schrijven van spaghetticode .
Externe bronnen
bewerken- Robert W. Sebesta, Concepts of Programming Languages, Addison-Wesley Publishing Company Inc., ISBN 0-8053-7133-8.
- Michael Sipser, Introduction to the Theory of Computation, PWS Publishing Company, ISBN 0-534-94728-X.