Functies
U maakt een Functie door een reeks instructies tussen { en } te zetten.
{ :graden
Uit schrijf: (graden * 1,8 + 32), stop.
} * 30.
We produceren deze reeks door de taak tussen de accolades {} te vermenigvuldigen met het getal 30.
>> graden := 0.
{
Uit schrijf: (graden * 1,8 + 32), stop.
graden optellen: 1.
} zolang: { <- (graden ≤ 30). }.
Bovenstaand fragment geeft dezelfde uitvoer, maar gebruikt een zolang-lus. U kunt een functie ook uitvoeren door het bericht start te verzenden.
{ Uit schrijf: 123, stop. } start.
Als uw functie argumenten accepteert, gebruikt u toepassen:.
{ :a Uit schrijf: a, stop. } toepassen: a.
Vanwege de eenvoudige architectuur kan een functie slechts één retourpunt hebben. Om overhead of overmatige nesting voor voorwaarden te vermijden, kunt u het bericht afbreken gebruiken in combinatie met een procedure (wat hetzelfde is als het gebruik van het vermenigvuldigingsteken met argument 1):
{
(a = 1) ja: { x := 1. }, afbreken.
(a = 2) ja: { x := 2. }, afbreken.
} procedure.
Op deze manier wordt (a = 2) niet geëvalueerd als a = 1. Ook heeft u op deze manier geen geneste ja-berichten nodig.
Denk altijd aan het bericht van de procedure als u voorwaarden nestelt. Het kan de code leesbaarder maken.
Hier is een belangrijke valkuil:
{
Nee nee: {
Uit schrijf: ['Einde van de lus.'].
}, afbreken.
Uit schrijf: ['Niet weergeven.'].
} procedure.
In dit geval wordt de tekst ‘Niet weergeven’ weergegeven.
Omdat afbreken naar Nee wordt gestuurd. Als u afbreken wilt uitvoeren, moet dit als bericht naar Ja worden gestuurd.
{
Nee niet ja: {
Uit schrijf: ['Einde van de lus.'].
}, afbreken.
Uit schrijf: ['Niet weergeven.'].
} procedure.
``
Zal werken zoals verwacht.
## Uitzonderingen
Een alternatieve manier om de loop van het computerprogramma te beïnvloeden is door een stuk
code met afhandelingen te definiëren in het geval van een fout. Stel dat een budgetapplicatie het
maandelijks budget moet vaststellen op basis van een door de gebruiker opgegeven inkomen en het
aantal maanden.
budget := jaarinkomen / maanden. ```
Wat gebeurt er nu als het aantal maanden op de één of andere manier 0 blijkt te zijn? Dan krijgen we een foutmelding:
Onafgehandelde fout opgetreden.
Deling door nul.
De eerste regel van het foutbericht geeft aan dat er zich een fout heeft voorgedaan die niet werd afgehandeld door het programma. De tweede regel in de uitvoer vertelt waar het probleem hem precies in zit: delen door nul is niet toegestaan. De eerste zin verraadt ook dat u dus een fout kunt afhandelen. Dit is ook een vorm van voorwaardelijke uitvoering van code, alleen nu gaan we een stuk code schrijven dat wordt uitgevoerd in het geval dat een ander stuk code een fout oplevert.
Stel dat we bijvoorbeeld het foutbericht willen aanpassen, dan doen we dat zo:
{
>> budget := jaarinkomen / maanden.
} afhandelen: {
Uit schrijf: ['Mag niet!'], stop.
}, start.
In dit geval zal het resultaat zijn (bij 0 maanden):
Mag niet!
Zichtbaarheid
U weet dat u een object kunt toewijzen aan een variabele, maar u moet wel eerst een plek in het geheugen reserveren onder deze naam, dat doet u met het aanwijspictogram. Dit noemen we het declareren van een variabele. In de voorgaande hoofdstukken hebben we dit allemaal al besproken. Niet alle delen van het geheugen zijn overal zichtbaar, want in grote programma’s waarin u ook code van derden verwerkt zou u anders bijna zeker in elkaars vaarwater terecht komen. Om die reden worden deze geheugenplekken van elkaar gescheiden, hierbij vormen taken de scheidslijnen. Er geldt dat een variabele die binnen een taak is gedeclareerd alleen zichtbaar is tijdens de uitvoering van die taak en tijdens de uitvoering van alle taken die door deze taak worden gestart. Als de taak waarin de variabele is gedeclareerd is afgelopen, wordt deze variabele vergeten. Bekijk het volgende voorbeeld eens:
>> x := 9.
{ Uit schrijf: x.
} start.
Het bovenstaande programma drukt het getal 9 af op het scherm. Objectnaam x is buiten de taak gedeclareerd en is dus overal zichtbaar, voor alle taken, dus ook wanneer we x als argument meesturen aan het Pen-object. U kunt het gebied buiten de taak beschouwen als een soort overkoepelende taak. Alle variabelen die u hier declareert zijn overal in het programma zichtbaar, immers, alle taken vallen als het ware binnen deze overkoepelende taak. We noemen variabelen die u buiten alle taken in het programma declareert ook wel globale variabelen vanwege hun globale zichtbaarheid.
{ >> x := 9. } start.
Uit schrijf: x.
In dit geval krijgen we een foutmelding. Objectnaam x is namelijk vergeten zodra de taak is afgelopen. Aangezien x is gedeclareerd binnen de taak is hij daarbuiten niet zichtbaar. In dit geval leeft x dus exclusief binnen het kleine taakje dat we hebben uitgeschreven. Kijk nu eens naar het volgende fragement, er komt geen foutmelding, maar welk getal gaat er op het scherm verschijnen?
>> x := 1.
{ >> x := 9. } start.
Uit schrijf: x.
Het juiste antwoord is 1, niet 9. Er zijn in dit geval twee plekken in het geheugen met de naam x. Dankzij de afbakening tussen de taken storen ze elkaar niet. Tijdens de uitvoering van de taak is x gelijk aan 9, en zodra die taak is afgelopen, wordt de andere x weer zichtbaar en is x gelijk aan 1.
Nu de lastigste versie:
>> y := { x := 2. }.
{ >> x := 1. y start. Uit schrijf: x. } start.
Wat gaat er op het scherm verschijnen, 1 of 2? Eerst reserveren we een plek in het geheugen onder naam y voor een taak. In die taak wordt getal 2 opgeslagen onder de naam x. Deze taak wordt echter niet gestart. Op de tweede regel maken we een nieuwe taak die meteen wordt gestart. In deze nieuwe taak declareren we x. We reserveren dus een plek in het geheugen onder de naam x. Onder de naam x slaan we vervolgens het getal 1 op. Op dat moment is x = 1. Dan wordt de taak met de naam y gestart die we op de eerste regel van ons programma hebben geschreven. Tijdens de uitvoering van die taak wordt het getal 2 opgeslagen onder de naam x. Kan dat? Het antwoord hierop is: ja. De cruciale regel is hier namelijk tijdens de uitvoering. Hoewel taak y visueel gezien niet binnen de taak op regel 2 valt, wordt taak y wel uitgevoerd tijdens de uitvoering van de taak op de tweede regel. Dit betekent dat de 1 die in x zat, wordt overschreven met het getal 2. Dus op dit moment is x = 2. Vervolgens is de taak y afgelopen en keert de uitvoering van het programma terug naar de taak op de tweede regel, klaar om x af te drukken op het scherm. Maar wat zit er nu in x? Functie y is immers afgelopen? Dat klopt, maar x is buiten y gedeclareerd, namelijk in de taak waarin we nu bezig zijn, de taak op de tweede regel, dus x bevat nog steeds het getal 2 en dus wordt dit ook zichtbaar op het scherm. Het mechanisme dat ik hier zojuist beschreven heb, wordt ook wel Dynamic Scoping genoemd.