Basis
XOScript is een pure objectgeoriënteerde programmeertaal. Dat wil zeggen dat alles in XOScript een object is. Er zijn verder geen andere datatypen. Een computerprogramma dat geschreven is in XOScript kan grofweg uit drie soorten handelingen bestaan: toewijzen, berichten sturen en antwoorden. De uitwisseling van berichten tussen objecten is het belangrijkste onderdeel van een XOScript-programma.
Variabelen
Om een variabele te declareren, gebruikt u het aanwijspictogram: >>. Een naam van een variabele mag uit alle tekens bestaan behalve <-, :=, spaties, punten, komma’s, dubbele punten, dubbele aanhalingstekens [‘‘] en boogjes (). Ook mag een variabelenaam geen meerdere regels beslaan. In plaats van een spatie mag u voor de leesbaarheid wel de haarspatie gebruiken in een variabelenaam. Een variabele mag verder niet beginnen met een getal of een minteken.
Hier zijn voorbeelden van geldige variabelen:
>> wachtwoord := ['Geheim'].
>> ♡♡♡ := 3.
>> $ := ['dollar'].
>> +plus := Ja.
>> wachtwoord-van-gebruiker := ['Pssst!'].
Ongeldige namen zijn bijvoorbeeld:
>> -123 := ['Negatief getal'].
>> wachtwoord van gebruiker := ['Geheim'].
>> wachtwoord.van:gebruiker := ['Geheim'].
>> ,x := 10.
Nadat een variabele is gedeclareerd, kan deze vrijelijk worden gebruikt. U hoeft het aanwijspictogram dus alleen bij de eerste keer dat u de variabele gebruikt (de declaratie) te gebruiken. U mag dus niet zomaar beginnen met het toewijzen van een waarde aan uw variabele (x := 2), u moet de variabele eerst declareren (>> x := 2). Eenmaal gedeclareerd mag u de waarde wel wijzigen zonder aanwijspictogram (>> x := 2. x := 3.). Let erop dat u verplicht bent om bij het declareren van een variabele een waarde toe te kennen. In tegenstelling tot andere programmeertalen mag u geen variabele declareren zonder waarde. U dient elke variabele expliciet te voorzien van een beginwaarde. U mag de variabele wel initialiseren met het Niets-object als u dat wilt, in dat geval kan de variabele beschouwd worden als zijnde leeg (>> x := Niets.).
Objecten
XOScript ‘denkt’ in objecten. Alles is een object. Alle getallen, teksten en stukken code. Getallen zoals 1, 2, 100, -999 en 1,234 zijn Getal-objecten. Teksten tussen aanhalingstekens zijn Tekstobjecten. Stukken code die gegroepeerd zijn door middel van accolades {…} zijn Functie-objecten.
Objecten zoals getallen en teksten stammen altijd af van een moederobject. Alle getallen zijn bijvoorbeeld afgeleid van het object Getal. Alle stukken code van Functie. Alle teksten van Tekst. Deze objecten stammen, op hun beurt weer af van Object, dit is het moederobject van alle objecten.
Berichten
U schrijft een XOScript-programma door berichten naar objecten te sturen. De algemene notatie voor het sturen van een bericht naar een object is:
<object> <bericht>
Willen we bijvoorbeeld weten of het getal 2 een even getal is, dan kunnen we het bericht even? sturen naar het object 2:
2 even?
Het antwoord dat we terug krijgen is Ja (ook weer een object). Onbekende berichten worden meestal door objecten genegeerd, er komt dus geen foutmelding. Sommige objecten (zoals getallen en teksten) reageren op een vooraf afgesproken manier op het ontvangen van een onbekend bericht (hierover later meer). Bovenstaande operatie geeft als resultaat ook weer een object, het Ja-object. Er zijn drie soorten berichten die u kunt sturen naar een object. Ten eerste is er het enkelvoudig bericht, zoals hierboven, dat is een bericht zonder argumenten. Ten tweede is er het meervoudige bericht, met één of meer argumenten:
>> x := Getal tussen: 1 en: 10.
In dit geval sturen we het bericht tussen:en: naar Getal, dit is het moederobject van alle getallen. Het resultaat zal zijn, een willekeurig getal tussen 1 en 10 (eveneens een object). Ten derde is er het tweevoudige bericht, dit berichttype bestaat altijd uit slechts één teken en heeft altijd precies één argument:
2 + 3
Dit ziet eruit als een rekensom, maar in XOScript sturen we het bericht + naar 2, met als argument 3, waarop we als antwoord 5 terugkrijgen. U schrijft tweevoudige berichten doorgaans zonder dubbele punt, dit in tegenstelling tot meervoudige berichten, waarbij de argumenten altijd vooraf worden gegaan door een dubbele punt (meervoudige berichten mogen wel, net als tweevoudige berichten uit 1 teken bestaan, dus het meervoudige bericht a: is toegestaan). We kunnen tweevoudige berichten als volgt aaneenschakelen:
>> x := 3 + 2 - 1.
In het bovenstaande fragment sturen we eerst + 2 naar Getal-object 3, dat levert Getal-object 5 op, naar dit getal sturen we vervolgens - 1. De oplettende lezer zal opmerken dat deze conventie in strijd is met de rekenkundige volgorde van operatoren, dit is correct. XOScript negeert de rekenkundige volgorde van bewerkingen ten faveure van de consistentie van het berichtensysteem. De rekensom 2 + 3 * 5 geeft in XOScript dus het antwoord 25 en niet 17. Met boogjes kunt u de volgorde veranderen: 2 + (3 * 5) geeft wel 17. Sommige objecten geven zichzelf terug als antwoord op een bepaald bericht, dat is handig, want daarmee kunt u het gesprek met dit object continueren door een vervolgbericht te sturen:
Uit schrijf: [' hallo ']
kern
hoofdletters.
Resultaat:
HALLO
We sturen hier twee berichten naar het Tekst-object, eerst verwijder omliggende spaties en daarna hoofdletters. De nieuwe regel ertussen is voor de leesbaarheid en optioneel. Na een meervoudig bericht moeten we in dit geval wel een komma gebruiken om aan te geven dat er een nieuw bericht volgt, anders raakt XOScript in de war, dit is bijvoorbeeld het geval indien we het bericht schrijf: wensen op te volgen met een volgend bericht:
Uit schrijf: ['Hallo!'], stop.
We sturen hier eerst het bericht schrijf: en daarna stop naar de pen. Zonder de komma zou XOScript denken dat u stop naar Tekst Hallo! wilt sturen, een nutteloze exercitie.
In het vorige voorbeeld zouden we het stop-bericht ook met een komma toevoegen:
Uit schrijf: [' hallo '] kern hoofdletters, stop.
Met de komma hervat u dus de communicatiestroom met het eerdere object. Nog een voorbeeld:
Uit schrijf: 1 + 2 stop.
Is niet goed, want u stuurt stop naar 2.
Uit schrijf: 1 + 2, stop.
Is wel goed, u stuurt stop naar de Pen.
De volgorde van verwerking van berichten is: van links naar rechts, berichten tussen boogjes eerst, dan de enkelvoudige berichten, dan de tweevoudige berichten en tenslotte de meervoudige berichten. Dus in het volgende voorbeeld:
Uit schrijf: 0.5 afgerond + (2 - 1), stop.
leest XOScript van links naar rechts, dus eerst wordt het bericht schrijf gestuurd naar de pen, daarna het stop-bericht. Binnen het argument in het schrijfbericht leest XOScript van links naar rechts, dus eerst 0,5 afgerond en dan de +. Bovendien is afgerond een enkelvoudig bericht, dus dit bericht krijgt voorrang boven de +, vanwege de boogjes wordt 2 – 1 eerst uitgerekend en dan wordt 1 opgeteld bij het resultaat van 0,5 afgerond (1), zo verkrijgen we uiteindelijk het antwoord 2. Dit is dan ook het antwoord dat wordt opgeschreven, na de komma volgt het stop-bericht waarmee de cursor op een nieuwe regel wordt gezet. De beste manier om de volgorde van XOScript-programma’s goed te doorgronden is ermee te oefenen.
Let op het gebruik van spaties, in tegenstelling tot veel andere programmeertalen spelen spaties een belangrijke rol in XOScript. Vooral bij tweevoudige berichten kunnen spaties verwarrend zijn. U moet een spatie gebruiken na een tweevoudig bericht, u mag niet direct een getal vastplakken aan het bericht: 3 + 2 is iets anders dan 3 +2. Het eerste voorbeeld (3 + 2) is het bericht + naar getal 3 met als argument het getal 2, het resultaat is 5. Het tweede voorbeeld (3 +2) is het enkelvoudige bericht +2 naar getal 3. Aangezien +2 standaard niet is gedefinieerd in XOScript zal de uitkomst daarom gelijk zijn aan 3 +2. Als een getal een bericht niet kent, zal het worden opgevat als kwalificering, zoals ‘liters’ of ‘meters’ en de tekst zal bij het getal gevoegd worden. Meer hierover in hoofdstuk 3. Indien u het bericht +2 wel gedefinieerd zou hebben dan zou de uitvoering van (3 +2) wel degelijk een resultaat kunnen hebben, maar dat ligt dan aan de door u opgestelde definitie van het bericht, dus als +2 bijvoorbeeld 1 zou optellen bij het ontvangende bericht zou u ervoor kunnen zorgen dat 3 +2 als antwoord 4 geeft!
Let op! Berichten mogen niet beginnen met een getal of minteken. Berichten mogen ook geen speciale tekens bevatten zoals { }, dubbele punten, boogjes, punten of komma’s.
Onbekende berichten
Het verzenden van een bericht naar een object roept de functie aan die aan dit object is gekoppeld onder de naam van dat bericht. Als u een bericht verzendt dat niet wordt begrepen, negeert het ontvangende object uw bericht en retourneert in plaats daarvan een verwijzing naar zichzelf voor verdere communicatie.
Dit wordt tolerante berichtoverdracht genoemd.
Voorbeeld:
Uit: Object blah, stop.
Dit geeft geen foutmelding. Het print simpelweg de tekst Object.
Programmaverloop
Voor lussen en voorwaardelijke uitvoering van code (for en ifs) zijn in XOScript geen aparte grammaticaregels nodig, een if-statement is niks meer dan het bericht ja: of nee: naar een Jaobject, of een Nee-object:
2 even? ja: {
Uit
schrijf: ['Twee is een even getal.'],
stop.
}.
Ja/Nee-objecten noemen we ook wel beslissingsobjecten. Deze naamgeving is soms duidelijker omdat het aangeeft dat we deze objecten gebruiken om het programma bepaalde beslissingen te laten nemen. Net als andere programmeertalen, volgt een programma geschreven in XOScript een bepaalde route en kent het vertakkingen. De gekozen paden binnen een programma worden voor een groot deel bepaald door deze beslissingsobjecten. In dit geval sturen we het bericht ja: naar Ja (het antwoord op de vraag of 2 een even getal is). Als argument sturen we een ander stukje code mee, namelijk een Functie-object. Deze taak schrijft op het scherm dat 2 een even getal is. Evenmin hebben we aparte schrijfregels nodig voor een lus, willen we bijvoorbeeld een stuk code 3 keer uitvoeren, dan sturen we * met argument 3 naar die code:
{ Uit schrijf: ['♣'], stop. } * 3.
Resultaat:
♣
♣
♣
Willen we bijvoorbeeld een omzettingstabel afdrukken van kj (kilojoules) naar kcal (kilocalorie) in stappen van 100, dan schrijven we:
{ :regel
>> aantal := regel * 100.
Uit schrijf: aantal, stop.
Uit schrijf: aantal * 0.239, stop.
} * 10.
Dit programma produceert de volgende lijst:
100
23.9
200
47.8
...
800
191.2
900
215.1
1000
239
Hierbij wordt het nummer van de huidige regel doorgegeven in de parameter :regel. Aan het begin van een taak worden de parameters gedefinieerd. Ongebruikte parameters blijven leeg (Niets). Parameters staan altijd aan het begin van de taak, direct na de openingsaccolade en worden voorafgegaan door een dubbele punt.
Het zolang-bericht vormt eigenlijk een combinatie tussen een herhaling en een voorwaardelijke uitvoering. Met het bericht zolang kunt u twee taken aan elkaar knopen. De ontvangende taak voert zichzelf net zo lang uit totdat de taak na de dubbele punt een negatief resultaat geeft. In de praktijk ziet dat er zo uit:
>> x := 0.
{ x optellen: 1. }
zolang: { <- x < 5. }.
Uit schrijf: x, stop.
Resultaat:
5
In het bovenstaande codefragment tellen we net zolang 1 op bij x todat x niet langer kleiner is dan 5, op dat moment antwoordt de tweede taak met Nee en wordt de uitvoering van de eerste taak gestaakt.
Sjablonen
De kj/kcal-lijst uit het vorige hoofdstuk is nog niet zo netjes, liever zouden we iets zien als:
100 kj ➞ 23,9 kcal
...
Als we de gewenste uitvoer omzetten naar een sjabloon, dan zouden we dit kunnen noteren als: getal1 kj ➞ getal2 kcal Hierbij is getal1 dus de kj-waarde en getal2 de kcal-waarde. In XOScript is dit hoe tekenreeksinterpolatie werkt. XOScript heeft geen aparte grammaticaregels nodig hiervoor, u stuurt gewoon het te vervangen woord naar de tekst met als argument de vervangende tekst:
>> tekst := ['getal1 kj ➞ getal2 kcal']
getal1: 100,
getal2: 23.9.
Het resultaat:
100 kj ➞ 23.9 kcal
Deze substitutieregel werkt voor elk ongedefinieerd bericht dat ontvangen wordt door een Tekstobject. Elk bericht dat het Tekst-object niet herkent, wordt begrepen als: vervang de tekst die het bericht vormt door de tekst in het argument van het bericht.
Passen we nu ons programma aan, dan krijgen we:
{ :regel
>> kj
:= regel * 100.
>> kcal := regel * 0.239.
Uit schrijf: (
['getal1 kj ➞ getal2 kcal']
getal1: kj,
getal2: kcal
), stop.
} * 10.
Als er verwarring dreigt op te treden over welk bericht nu wel of niet gebruikt mag worden voor substitutie, dan kunt u voor de zekerheid de te vervangen tekstsegmenten in het sjabloon vooraf laten gaan door een betekenisloos teken, zoals de lozenge ⬧ (U+2B27, ALT+Z). In internationale context is dit soms aan te raden.
Respons
Tot nu toe hebben we berichten gestuurd naar objecten, maar nog nooit zelf repons gegeven. Om te antwoorden op een bericht, gebruikt u het antwoordpijltje (<-). In het volgende voorbeeld maken we een taak om een percentage te berekenen:
>> percentage := { :getal :procent
<- getal / 100 * procent.
}.
percentage toepassen: 100 en: 7.
Nadat we de taak hebben gedefinieerd en toegewezen aan variabele percentage sturen we het bericht toepassen:, met argumenten 100 en 7. Hiermee wordt de taak uitgevoerd, toegepast op 100 en 7. Zo nemen we 7% van 100. Met de pijl sturen we het antwoord vanuit de taak terug naar het hoofdprogramma.
Uitbreiden
Hoewel deze code geldig is, kleeft er een nadeel aan, we moeten namelijk de volgorde van de argumenten onthouden. Waarom kunnen we het niet zo opschrijven: 7 procent van: 100 ? Om dat mogelijk te maken moeten we het moederobject van 7, het Getal-object aanpassen zodat het het bericht procent van: begrijpt. Dat doen we door bij:doen: te sturen naar het Getal-object met als argument de uit te voeren taak:
Getal bij: ['procent-van:'] doen: { :getal
>> procent := zelf.
}.
<- getal / 100 * procent.
Het bericht bij:doen: wordt begrepen door Object, het moederobject van alle objecten. Op het moment dat Object dit bericht ontvangt zal het het kindobject, in dit geval Getal, uitbreiden met de opgegeven taak tussen de accolades {} en deze taak koppelen aan het bericht van onze keuze, namelijk procent van:. U kunt dus de functionaliteit van objecten uitbreiden met hetzelfde mechanisme als waarmee u de functionaliteiten aanspreekt: via berichten. Een taak welke deel uitmaakt van een object wordt ook wel een ‘methode’ genoemd. Omdat het percentage in dit geval het getal zelf is, verwijzen we naar zelf, het zelf symbool. Het pictogram zelf betekent dus: stuur dit bericht naar mijzelf. Na het uitvoeren van bovenstaande code, kunnen we zeggen:
Uit schrijf: (7 procent-van: 100), stop.
Het resultaat van deze operatie is natuurlijk 7.