20.08.2013 Views

Sina/st - trese - Universiteit Twente

Sina/st - trese - Universiteit Twente

Sina/st - trese - Universiteit Twente

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Universiteit</strong> <strong>Twente</strong><br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong><br />

faculteit der<br />

informatica<br />

On the Definition and<br />

Implementation of the<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

M.Sc. Thesis<br />

Piet S. Koopmans<br />

Augu<strong>st</strong> 25, 1995


On the Definition and<br />

Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong><br />

Language<br />

Graduation Committee:<br />

Dr.Ir. M. Aksit (supervisor)<br />

Dr.Ir. L.M.J. Bergmans<br />

Ing. R.R. van de Stadt<br />

M.Sc. Thesis<br />

by<br />

Piet S. Koopmans<br />

Enschede<br />

Augu<strong>st</strong> 25, 1995


Ab<strong>st</strong>ract<br />

The object-oriented paradigm provides features that are very useful to obtain extensible,<br />

reusable, and robu<strong>st</strong> software. The conventional object-oriented model supports objects,<br />

classes, encapsulation, inheritance, part-whole relations, and polymorphic message<br />

passing. The current object oriented methods, languages and tools, however, have a<br />

number of deficiencies that make them less suitable for certain categories of applications.<br />

For this, the TRESE project of the University of <strong>Twente</strong>, the Netherlands developed the<br />

composition filters object model which is capable of solving a number of the deficiencies.<br />

The composition filters object model, an extension to the object-oriented model,<br />

introduces input and output composition filters which affect the received and sent<br />

messages respectively. The programming language <<strong>st</strong>rong>Sina</<strong>st</strong>rong> is used to express the concepts of<br />

the composition filters object model. <<strong>st</strong>rong>Sina</<strong>st</strong>rong> is a real-time concurrent object-oriented<br />

programming language which adopts the composition filters object model.<br />

This thesis describes the definition and the implementation of the concurrent object-oriented<br />

programming language <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> , a Smalltalk implementation of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>. The syntax and<br />

semantics of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language are described and illu<strong>st</strong>rated with numerous examples.<br />

We introduce techniques for the implementation of composition filters. The<br />

implementation addresses the specific features of the composition filters object model:<br />

reflection on messages, concurrency and synchronization.<br />

One of the five filters that are provided by this implementation, allows to ab<strong>st</strong>ract<br />

communications among objects into a fir<strong>st</strong>-class object called ab<strong>st</strong>ract communication<br />

type (ACT). After an ACT has gained control over a received or sent message, it can<br />

release the message by letting the message follow its further course, or by supplying a<br />

reply for the message. In addition to these two methods, we introduces a new way to<br />

release the message. This allows an ACT to regain control over a message as soon as this<br />

message receives a reply object.<br />

The presented <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation provides a programming environment, which<br />

includes a user interface that allows the user to edit, compile and execute a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

application, a compiler that translates <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> source code to Smalltalk, and a kernel for<br />

run-time support. This environment can be used to verify and implement applications<br />

which adopt the composition filters object model.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

iii


iv<br />

Samenvatting<br />

Het object-georiënteerde paradigma heeft eigenschappen die zeer nuttig zijn voor het<br />

ontwikkelen van uitbreidbare, herbruikbare en robuu<strong>st</strong>e software. Het conventionele<br />

object-georiënteerde model biedt objecten, klassen, overerving, part-whole relaties en<br />

polymorfe message passing. De huidige object-georiënteerde methoden, programmeertalen<br />

en gereedschappen hebben echter een aantal tekortkomingen waardoor ze minder<br />

geschikt zijn voor bepaalde categorieën van applicaties.<br />

Hiertoe heeft het TRESE project van de <strong>Universiteit</strong> <strong>Twente</strong> (Enschede, Nederland) het<br />

compositie filters object model ontwikkeld. Het compositie filters object model is een<br />

uitbreiding van het object-georiënteerde model en kan een aantal van de tekortkomingen<br />

van dit model oplossen. Het compositie filters object model beschikt over invoer en<br />

uitvoer compositie filters die respectievelijk ontvangen en verzonden berichten<br />

beïnvloeden. De programmeertaal <<strong>st</strong>rong>Sina</<strong>st</strong>rong> maakt het mogelijk om de concepten van dit model<br />

uit te drukken. <<strong>st</strong>rong>Sina</<strong>st</strong>rong> is een real-time, concurrente, object-georiënteerde programmeertaal<br />

die gebruik maakt van het compositie filters object model.<br />

Dit doctoraalverslag beschrijft de definitie en implementatie van de concurrente, objectgeoriënteerde<br />

programmeertaal <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> , een Smalltalk implementatie van <<strong>st</strong>rong>Sina</<strong>st</strong>rong>. De syntax<br />

en semantiek van <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> worden beschreven en geïllu<strong>st</strong>reerd met diverse voorbeelden.<br />

In het verslag worden verder technieken voor het implementeren van compositie filters<br />

geïntroduceerd. Daarbij wordt rekening gehouden met de specifieke eigenschappen van<br />

het compositie filters object model, zoals reflectie op berichten, concurrentie en<br />

synchronisatie.<br />

Een van de vijf filters die deze implementatie biedt, maakt het mogelijk om communicatie<br />

tussen objecten te ab<strong>st</strong>raheren in fir<strong>st</strong>-class objecten, welke ab<strong>st</strong>racte communicatie typen<br />

(ACT) worden genoemd. Nadat een ACT controle over een ontvangen of verzonden<br />

bericht heeft verkregen, kan deze het bericht weer vrijgeven door het bericht zijn normale<br />

gang te laten gaan, of door een antwoord-object voor het bericht beschikbaar te <strong>st</strong>ellen. Dit<br />

doctoraalverslag introduceert een nieuwe mogelijkheid voor het vrijgeven van het bericht.<br />

Hiermee krijgt de ACT weer controle over het bericht zodra het bericht een antwoordobject<br />

krijgt.<br />

De beschreven <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementatie heeft de beschikking over een programmeeromgeving<br />

die be<strong>st</strong>aat uit een gebruikers interface waarmee de gebruiker <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> applicaties<br />

kan schrijven, vertalen en uitvoeren. Daarnaa<strong>st</strong> heeft de programmeer-omgeving een<br />

vertaler die <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> bron code vertaalt naar Smalltalk, en een kern voor onder<strong>st</strong>euning<br />

tijdens run-time. Deze programmeer-omgeving kan worden gebruikt voor het verifiëren en<br />

implementeren van applicaties die gebruik maken van het compositie filters object model.<br />

Samenvatting


Voorwoord<br />

Met het voltooien van dit doctoraal verslag zit mijn <strong>st</strong>udie Informatica aan de <strong>Universiteit</strong><br />

<strong>Twente</strong> in Enschede er dan eindelijk op. Ondanks een aantal moeilijkheden die ik<br />

ondervond, heb ik met veel plezier bij het TRESE project aan mijn doctoraal opdracht<br />

gewerkt. Vooral het afgelopen half jaar is <strong>st</strong>imulerend gewee<strong>st</strong> voor het afronden van mijn<br />

<strong>st</strong>udie. In deze periode heb ik, naa<strong>st</strong> het af<strong>st</strong>uderen, ook nog aan andere activiteiten binnen<br />

het TRESE project mogen meewerken.<br />

Ik wil dan ook Mehmet Aksit, Lodewijk Bergmans en Richard van de Stadt hartelijk<br />

bedanken. Niet alleen voor de technische adviezen tijdens het af<strong>st</strong>uderen, maar vooral ook<br />

voor het vertrouwen, en de aanmoedigingen om door te gaan.<br />

Daarnaa<strong>st</strong> wil ik ook Bonne van Dijk noemen. Met hem heb ik vele discussies mogen<br />

voeren en ook hij heeft mij ge<strong>st</strong>imuleerd om door te zetten.<br />

Tot slot wil ik mijn kamergenoten Bedir Tekinerdogan en Francesco Marcelloni bedanken.<br />

De gezamenlijke koppen koffie en thee zijn niet meer te tellen.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

Piet S. Koopmans<br />

Enschede, 30 augu<strong>st</strong>us 1995<br />

v


Contents<br />

Part i Introduction 1<br />

1 Introduction 3<br />

1.1 Deficiencies in object-oriented technology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />

1.2 The composition filters object model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />

1.2.1 Solving modeling problems with composition filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

1.3 The pa<strong>st</strong>, present, and future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

1.4 Problem <strong>st</strong>atement and approach of this thesis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

1.5 Outline of this thesis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

Part ii Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language 13<br />

2 Language survey 15<br />

2.1 The composition filters object model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

2.1.1 The inner object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

2.1.2 The composition filters object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

2.2 A composition filters object in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />

2.2.1 The interface part . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

2.2.2 The implementation part . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

2.2.3 The main method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

2.3 Forthcoming chapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

2.3.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

2.3.2 Terminology. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

2.3.3 Structure of a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

2.3.4 Where to find what . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

3 Basic language elements 23<br />

3.1 Comment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

3.2 Literal con<strong>st</strong>ants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

3.2.1 Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

3.2.2 Strings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

3.2.3 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

3.2.4 The con<strong>st</strong>ants nil, true and false . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

3.3 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

3.3.1 Declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

3.3.2 Typedescription. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

3.3.3 Initial value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

3.3.4 Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

3.4 Global externals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

vii


viii<br />

3.5 Pseudo variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />

4 Expressions 31<br />

4.1 Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />

4.2 Message expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />

4.3 Operator expression. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .33<br />

5 Control <strong>st</strong>ructures 37<br />

5.1 The conditional <strong>st</strong>atement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

5.2 The for <strong>st</strong>atement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

5.3 The while <strong>st</strong>atement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .38<br />

6 Classes and in<strong>st</strong>ances 39<br />

6.1 Class declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />

6.1.1 The interface part . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />

6.1.2 The implementation part. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .40<br />

6.1.3 Class switches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40<br />

6.2 An in<strong>st</strong>ance of a class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .43<br />

6.3 The object manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .44<br />

7 Methods 45<br />

7.1 Interface method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

7.2 Private method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

7.3 Initial method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

7.4 Main method. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

7.5 Returning a value from a method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

7.6 Normal versus early return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />

7.7 Method invocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54<br />

7.8 Statements in a method body. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56<br />

8 Conditions 57<br />

8.1 Condition declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57<br />

8.2 Condition implementation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />

8.3 Using a condition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

9 Filters 61<br />

9.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61<br />

9.2 Input and output filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62<br />

9.3 Filterdeclaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

9.3.1 Reused filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

9.3.2 Local filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

9.3.3 Rewrite rules for filterelements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65<br />

9.4 Filtering a message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66<br />

9.5 The signature of an object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68<br />

9.6 Filterhandlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69<br />

9.6.1 Dispatch filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70<br />

9.6.2 Error filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70<br />

9.6.3 Send filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70<br />

9.6.4 Wait filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70<br />

9.6.5 Meta filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71<br />

Contents


10 Message passing semantics 73<br />

10.1 Sending a message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73<br />

10.2 The pseudo variable message and class ActiveMessage . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

10.3 Concurrency with threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

10.4 Message reification and dereification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />

10.4.1 Message reification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />

10.4.2 Message dereification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78<br />

10.4.3 Multiple reifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83<br />

10.4.4 Writing ACT methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85<br />

10.5 The class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86<br />

Part iii Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language 89<br />

11 Implementation Approach 91<br />

11.1 Problem <strong>st</strong>atement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />

11.2 Approach. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93<br />

11.3 Overview of the implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94<br />

12 Execution Model 95<br />

12.1 Overview of message execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />

12.2 Representation of an active message. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97<br />

12.3 Filtering a message. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />

12.3.1 Message handling by a filter group . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />

12.3.2 Message handling by a filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103<br />

12.3.3 The signature of an object and signature matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />

12.4 Filter handler classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />

12.4.1 Dispatch filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />

12.4.2 Error filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109<br />

12.4.3 Send filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109<br />

12.4.4 Meta filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109<br />

12.4.5 Wait filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109<br />

12.5 Method invocation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109<br />

12.5.1 Normal and early returning methods. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111<br />

12.6 Message reification and dereification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .112<br />

12.7 Synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116<br />

12.8 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> messages to Smalltalk objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .118<br />

13 Translation Model 119<br />

13.1 General object model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .119<br />

13.2 In<strong>st</strong>ance creation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120<br />

13.3 Detecting if a method returns normal or early. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121<br />

13.4 Mapping <<strong>st</strong>rong>Sina</<strong>st</strong>rong> to Smalltalk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124<br />

14 Programming environment 127<br />

14.1 Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />

14.2 User interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />

14.3 Kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

ix


x<br />

Part iv Evaluation and Conclusions 133<br />

15 Evaluation 135<br />

15.1 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135<br />

15.2 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136<br />

15.2.1 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136<br />

15.2.2 Encountered problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137<br />

15.2.3 Known bugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137<br />

15.2.4 Performance comparison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137<br />

16 Conclusions 141<br />

16.1 Overview and contributions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

16.1.1 Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

16.1.2 Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

16.2 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />

16.3 Future work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />

Part v Appendices 145<br />

A <<strong>st</strong>rong>Sina</<strong>st</strong>rong> Class Interfaces 147<br />

A.1 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147<br />

A.2 ActiveMessage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148<br />

A.3 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149<br />

A.4 ObjectManager. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150<br />

B Using Smalltalk classes in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> 151<br />

B.1 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> variable declaration using a Smalltalk class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151<br />

B.2 Smalltalk selectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />

C <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> syntax definition 155<br />

C.1 Token class specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

C.2 Grammar specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156<br />

D Conversion algorithm 165<br />

D.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165<br />

D.2 A closer look at the filter initializer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166<br />

D.3 Definitions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167<br />

D.4 The algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169<br />

References 173<br />

Index 177<br />

Contents


PART<br />

i Introduction<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong><br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language


1 Introduction<br />

This thesis describes the definition and an approach for the implementation of the<br />

programming language <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> . <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> is a Smalltalk implementation of the concurrent<br />

object-oriented programming language <<strong>st</strong>rong>Sina</<strong>st</strong>rong>. The <<strong>st</strong>rong>Sina</<strong>st</strong>rong> language incorporates the<br />

composition filters object model which aims at solving a number of ob<strong>st</strong>acles that are not<br />

properly addressed by current object-oriented programming languages and software<br />

development methods. The fir<strong>st</strong> section of this chapter describes these shortcomings.<br />

Some of the deficiencies of conventional object-oriented technology can be solved by the<br />

composition filters object model. This object model is an extension to the conventional<br />

object-oriented model, and can express several concepts, such as inheritance, delegation,<br />

synchronization, reflection on communication among objects, and real-time specifications<br />

(section 1.2)<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> , <<strong>st</strong>rong>Sina</<strong>st</strong>rong> and the composition filters object model have been developed by the TRESE<br />

project 1 at the University of <strong>Twente</strong>, during several years of research. Section 1.3 gives an<br />

overview of their evolution.<br />

Section 1.4 defines the problem <strong>st</strong>atement, and describes the approach to the problem. This<br />

chapter ends by showing the outline of this thesis.<br />

1.1 Deficiencies in object-oriented technology<br />

The object-oriented model provides features that are very useful for a large category of<br />

applications to obtain extensible, reusable, and robu<strong>st</strong> software. The conventional objectoriented<br />

model supports objects, classes, encapsulation, inheritance, part-whole relations,<br />

and polymorphic message passing [Wegner87]. The current object oriented methods,<br />

languages and tools, however, have a number of deficiencies that make them less suitable<br />

for certain categories of applications.<br />

The TRESE project has carried out several pilot projects in order to identify the<br />

shortcomings of current object-oriented technology [Aksit92a] [Aksit95]. This research<br />

concludes that the deficiencies of the current object-oriented technology can be divided in<br />

methodological and modeling problems.<br />

1. <strong>Twente</strong> Research & Education on Software Engineering, a research project of the SETI group at the<br />

Department of Computer Science, University of <strong>Twente</strong>, Enschede, The Netherlands.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

3


4<br />

Methodological<br />

problems<br />

Methodological problems arise if object-oriented software development methods are<br />

utilized. The difficulties experienced in applying object-oriented analysis and design<br />

methods are addressed by other research.<br />

Modeling problems Modeling problems are due to the fact that object-oriented models are not capable of<br />

expressing certain aspects of applications. This category of problems is addressed by the<br />

composition filters object model.<br />

We now describe these modeling problems and indicate in which application domains they<br />

can be experienced. We classify application domains into a number of basic domains. A<br />

typical application may comprise several basic domains. The basic domains include<br />

application generators, concurrency and synchronization, con<strong>st</strong>raint sy<strong>st</strong>ems, control<br />

sy<strong>st</strong>ems, databases, di<strong>st</strong>ribution, knowledge processing, numerical (CAD) modeling, realtime,<br />

and user interfaces.<br />

After the composition filters object model has been introduced (section 1.2), it is<br />

demon<strong>st</strong>rated how composition filters can solve the modeling problems. The alphabetical<br />

li<strong>st</strong> of these problems and associated application domains is as follows:<br />

• Atomicity and inheritance (databases and di<strong>st</strong>ributed sy<strong>st</strong>ems)<br />

Atomic actions are a mechanism to preserve consi<strong>st</strong>ency, for example in databases<br />

where they are called transactions. Due to the conventional procedure-call like<br />

semantics of transactions, they do not integrate uniformly with object-oriented<br />

concepts, especially inheritance.<br />

• Coordinated behavior (control sy<strong>st</strong>ems, databases, di<strong>st</strong>ributed sy<strong>st</strong>ems, real-time<br />

applications and user-interfaces)<br />

Coordinated behavior can be encountered for example in control sy<strong>st</strong>ems, in which<br />

several di<strong>st</strong>inct units, such as controlling algorithms, sensors and actuators, mu<strong>st</strong> work<br />

together in order to keep the controlled sy<strong>st</strong>em in a consi<strong>st</strong>ent <strong>st</strong>ate.<br />

In the object-oriented model, objects interact with each other by sending messages,<br />

where the client object transmits a message to a server object, and depending on the<br />

synchronization semantics, it either waits until the server object explicitly returns from<br />

performing its task or continues with its processing. The object-oriented models do not<br />

provide high-level mechanisms to ab<strong>st</strong>ract coordinated behavior among several objects<br />

since message passing semantics only involves two partner objects. To implement<br />

coordinated behavior, the application code mu<strong>st</strong> be spread over several entities which<br />

means that the application becomes more complex, less reusable, while its interaction<br />

semantics is more difficult to enforce and verify.<br />

• Duality in conception between object databases and languages (databases)<br />

In mo<strong>st</strong> of the current object-oriented language-database sy<strong>st</strong>ems programming<br />

language and database models are <strong>st</strong>ill separated. There are special con<strong>st</strong>ructs<br />

separated from the language to access the database facilities, and often queries can only<br />

be applied on a fixed number of objects.<br />

• Dynamic inheritance and delegation (all application domains)<br />

Dynamic inheritance (dynamic delegation) means that the inheritance hierarchy<br />

(delegation <strong>st</strong>ructure) is not fixed, but that an object can specify a set of superclasses<br />

(delegated objects) from which it may possibly inherit (delegate to). Dynamic<br />

inheritance or delegation can be needed if an application mu<strong>st</strong> be able to adapt for<br />

performance reasons or space requirements, to different clients or contexts, or even to<br />

different hardware, as for example in di<strong>st</strong>ributed sy<strong>st</strong>ems.<br />

• Excessive class declarations (non-parameterized hierarchies) (all application<br />

domains)<br />

Excessive class declarations can be experienced when all meaningful combinations of<br />

classes mu<strong>st</strong> be composed with (multiple) inheritance and declared as a separate class.<br />

Chapter 1: Introduction


Because every possible combination mu<strong>st</strong> be represented explicitly in the inheritance<br />

hierarchy, this hierarchy easily becomes unmanageable.<br />

Consider for example a graphical application which needs to draw points on a display.<br />

The class Point represents such a display point. Class Hi<strong>st</strong>oryPoint inherits from Point<br />

and keeps a li<strong>st</strong> containing the sequence of locations the point has had. Class<br />

BoundedPoint has re<strong>st</strong>ricted display coordinates and also inherits from Point. Class<br />

BoundedHi<strong>st</strong>oryPoint combines the features of Hi<strong>st</strong>oryPoint and BoundedPoint and<br />

therefore inherits from both these two classes.<br />

Assume now that, for the drawing of lines, we want to define class SolidLine which<br />

inherits from Point. DashedLine inherits from SolidLine but draws dashed lines in<strong>st</strong>ead<br />

of solid lines. If all the combinations of these classes are meaningful then one needs to<br />

declare all the possible combinations as a separate class, such as Point, Hi<strong>st</strong>oryPoint,<br />

BoundedPoint, BoundedHi<strong>st</strong>oryPoint, SolidLine, DashedLine, Hi<strong>st</strong>orySolidLine,<br />

BoundedSolidLine, BoundedHi<strong>st</strong>orySolidLine, Hi<strong>st</strong>oryDashedLine, BoundedDashed-<br />

Line, BoundedHi<strong>st</strong>oryDashedLine. The inheritance hierarchy will grow further if we<br />

add more classes to the hierarchy. For example, creating class 3DimensionalPoint as a<br />

subclass of Point doubles the number of class declarations.<br />

• Fixed message passing semantics (concurrency and synchronization, user interfaces)<br />

Although message passing is a key feature in the object-oriented model, the semantics<br />

of message passing is fixed by the adopted language, or, at be<strong>st</strong>, can be selected from a<br />

limited set of fixed semantics. Message passing semantics may include remote<br />

procedure call mechanism, asynchronous message passing, broadca<strong>st</strong> and multica<strong>st</strong>ing<br />

of messages, and atomic message send semantics. In mo<strong>st</strong> languages, these<br />

fixed semantics cannot be tailored to model application specific interaction<br />

mechanisms, while it is even harder to ab<strong>st</strong>ract and reuse them.<br />

• Inheritance versus real-time (real-time sy<strong>st</strong>ems)<br />

When classes are reused in applications with different real-time behavior, changes to<br />

either the application requirements or the real-time specifications in subclasses may<br />

result in excessive redefinitions of superclasses while this may be intuitively<br />

unnecessary. This so called real-time specification anomaly can arise when real-time<br />

specifications have been mixed within the application code, when real-time<br />

specifications are not polymorphic (i.e. they cannot be used for more than one method),<br />

or when real-time specifications are orthogonally re<strong>st</strong>ricted (i.e. independently defined<br />

specifications cannot be combined through inheritance without redefinition of the<br />

related specifications).<br />

• Inheritance versus synchronization (concurrency and synchronization, user interfaces)<br />

Conflicts between inheritance and synchronization can appear when a class that<br />

implements synchronization is extended in a subclass by introducing new methods,<br />

overriding methods, or by adding synchronization con<strong>st</strong>raints. When this requires<br />

additional redefinitions, this problem is considered to be an inheritance anomaly2 .<br />

For in<strong>st</strong>ance, when synchronization code is mixed with the application code (i.e. inside<br />

a method), changing synchronization is impossible without affecting the application<br />

code. Another source for inheritance anomalies comes from the non-decomposability<br />

of synchronization specifications in some languages. It is thus hard to add a new<br />

synchronization con<strong>st</strong>raint, or to redefine a part of the synchronization specification in<br />

a subclass.<br />

• Multiple interfaces (views) (all application domains)<br />

Not all operations provided by an object are necessarily of intere<strong>st</strong> to other objects that<br />

use its services. Therefore it is desirable to define interfaces for an object,<br />

differentiating between clients, that is, between the senders of a message. For example,<br />

a public mailbox should make a di<strong>st</strong>inction between a po<strong>st</strong>man and others, since<br />

2. This term is not re<strong>st</strong>ricted to synchronization. If the introduction of a new method or overriding an inherited<br />

method in a subclass requires additional redefinitions, this problem is an inheritance anomaly, because this<br />

should not be necessary.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

5


6<br />

everybody is allowed to put a letter in it, but only a po<strong>st</strong>man is allowed to empty the<br />

mailbox.<br />

• Part-of versus inheritance (all application domains)<br />

A part in the analysis phase may be implemented by inheritance in the design phase,<br />

which means that there are conceptual differences between the analysis phase and<br />

design phase and this may result in changes in the object oriented model of the<br />

application. As an example, consider a rectangle. Conceptually, a rectangle can be<br />

described with two points, i.e. they are part of the rectangle. If we would like to<br />

emphasize reusability, a rectangle could be defined to inherit from class Point in<strong>st</strong>ead.<br />

• Lack of reflection (all domains, but typically in control sy<strong>st</strong>ems, di<strong>st</strong>ributed sy<strong>st</strong>ems,<br />

knowledge processing, and user interfaces)<br />

A reflective sy<strong>st</strong>em is a sy<strong>st</strong>em which incorporates models representing (aspects of)<br />

itself. This self representation is causally connected to the reflected entity, and<br />

therefore, makes it possible for the sy<strong>st</strong>em to answer que<strong>st</strong>ions about itself and support<br />

actions on itself. Conventional object-oriented methods and languages do not, or only<br />

provide a limited support for reflection.<br />

• Sharing behavior with <strong>st</strong>ate (all application domains)<br />

In conventional object-oriented models, classes cannot conveniently express sharing<br />

behavior that is affected by shared <strong>st</strong>ate information. This is because, in general,<br />

classes are used to share behavior while their in<strong>st</strong>ances <strong>st</strong>ore their respective <strong>st</strong>ates.<br />

Sharing behavior with <strong>st</strong>ate is needed, for in<strong>st</strong>ance, when we want to model a company<br />

with several departments. Every department has a secretary who takes care of making<br />

appointments (shared behavior), and maintains the common agenda (shared <strong>st</strong>ate) of<br />

the department’s employees. When an employee is asked to make an appointment, he<br />

delegates this reque<strong>st</strong> to the secretary who takes the agenda and fix a time and date<br />

based on the employee’s working hours.<br />

• Unmatched sy<strong>st</strong>em functionalities (all but specifically in con<strong>st</strong>raint sy<strong>st</strong>ems, databases,<br />

and di<strong>st</strong>ributed sy<strong>st</strong>ems)<br />

The operating sy<strong>st</strong>em generally provides services that are required by mo<strong>st</strong><br />

applications. However, some applications may require specific functionalities which<br />

are not supported by it. These then, mu<strong>st</strong> be implemented by the software engineer. For<br />

example, only a few operating sy<strong>st</strong>ems provide recovery mechanisms needed by a<br />

database application after a transaction has failed.<br />

1.2 The composition filters object model<br />

The composition filters object model extends the basic object-oriented model in a modular<br />

way. Its object model can be divided in two separate parts: an implementation part and an<br />

interface part. The implementation part is the kernel of an composition filters object and<br />

adheres to the conventional object-oriented model. The interface part is a layer that<br />

encapsulates the kernel object. This part contains the extensions which are made by the<br />

composition filters model. The interface part receives incoming messages, processes them,<br />

and optionally hands them over to the implementation part. The interface part additionally<br />

processes messages that are sent by the implementation part, and sends them to their<br />

respective targets.<br />

The extensions that are introduced by the composition filters object model comprise input<br />

and output composition filters. Input filters process received messages, while output filters<br />

process sent messages. Every filter has its own functionality which does not affect other<br />

filters: filters are orthogonal. Filters can be composed in arbitrary combinations. The<br />

combined functionalities of these filters are thus added to the kernel object (the<br />

implementation part).<br />

A filter specifies in a declarative way which messages it accepts. Whether the filter accepts<br />

a message depends on the message itself (typically its selector), and some designated<br />

Chapter 1: Introduction


conditions. These conditions can access the context of the message (e.g. its sender), and<br />

the <strong>st</strong>ate of its receiver.<br />

The composition filters object model defines the following filters:<br />

• dispatch filter: a dispatch filter offers a message to a specified target object for further<br />

processing. Conceptually, a dispatch filter realizes inheritance when the target object is<br />

encapsulated by (i.e. internal to) the receiver, and delegation when it is external to the<br />

receiver. In the former case, the target object represents the superclass. Associative<br />

inheritance and delegation3 is accomplished when conditions —which reflect the<br />

context or <strong>st</strong>ate of the receiver— are used to choose between several target objects.<br />

• wait filter: a wait filter is used to delay a message. Conditions specify the<br />

synchronization con<strong>st</strong>raints. The message is allowed to continue when the<br />

synchronization conditions are met;<br />

• meta filter: a meta filter suspends a message and offers it to a designated object. This<br />

object, an ab<strong>st</strong>ract communication type (ACT), manipulates the message and releases<br />

it again. A meta filter allows an ACT to reflect on communication among objects;<br />

• error filter: an error filter raises an error exception for a message;<br />

• real-time filter: a real-time filter is able to affect timing con<strong>st</strong>raints of a message;<br />

• send filter: a send filter offers a sent message its target.<br />

1.2.1 Solving modeling problems with composition filters<br />

The object-oriented modeling problems described in section 1.1 can be solved by using the<br />

composition filters object model. In this section we indicate how.<br />

• Atomicity and inheritance;<br />

Atomic messages have been introduced to support atomicity. Because they can be<br />

specified by every filter, atomic inheritance and delegation is provided for as well<br />

[Aksit91]. (this subject is not addressed by this thesis)<br />

• Coordinated behavior;<br />

An ab<strong>st</strong>ract communication type object can be used to coordinate the behavior among<br />

the group of objects. Messages between a pair of objects in this group can be<br />

intercepted by a meta filter, and offered to the coordinating object. Because the<br />

application code implementing the coordinated behavior has not been divided over the<br />

participating objects, it can be easily extended or replaced [Aksit93]. (refer to<br />

section 9.6.5, page 71 and section 10.4, page 77)<br />

• Duality in conception between object databases and languages;<br />

Database-like features can be accomplished by a dispatch filter, associative inheritance,<br />

and set operations. There is no separate language con<strong>st</strong>ruct for these features, while<br />

queries can be applied to all objects [Aksit92b]. (this subject is not addressed by this<br />

thesis)<br />

• Dynamic inheritance and delegation;<br />

This problem can be solved by using dispatch filter and associative inheritance c.q.<br />

delegation. Because conditions representing the context or <strong>st</strong>ate of the receiver are<br />

evaluated dynamically, the inheritance and delegation <strong>st</strong>ructure changes appropriately<br />

[Aksit92b]. (refer to section 9.6.1, page 70 and section 9.6.2, page 70)<br />

Behavior injection Alternative implementations can be realized with behavior injection. Behavior<br />

injection is defined as replacing or extending the behavior of an object dynamically<br />

(i.e. at run-time) with new behavior. In the composition filters object model this can be<br />

accomplished by replacing an object which is the target in a dispatch filter, with<br />

another object.<br />

3. By using associative inheritance and associative delegation, the client may affect the inheritance hierarchy,<br />

c.q. delegation <strong>st</strong>ructure to some extent.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

7


8<br />

• Excessive class declarations (non-parameterized hierarchies);<br />

The dispatch filter and associative inheritance can be used to avoid excessive class<br />

declarations. A client can choose the right combination of superclasses from the given<br />

ones by setting the appropriate conditions at in<strong>st</strong>ance creation time [Aksit92b]. (refer to<br />

section 6.1.1, page 39, section 9.6.1, page 70)<br />

• Fixed message passing semantics;<br />

By using meta filters and ab<strong>st</strong>ract communication types, we can introduce arbitrary<br />

message passing semantics. Every ab<strong>st</strong>ract communication type object can implement<br />

specific message passing semantics, such as asynchronous and future message passing.<br />

Because these ab<strong>st</strong>ract communication type objects are in<strong>st</strong>ances of ordinary classes,<br />

message passing semantics can be reused and extended [Aksit93][Bergmans94a].<br />

(refer to chapter 10)<br />

• Inheritance versus real-time;<br />

The real-time filter can change the timing con<strong>st</strong>raints of a message. Since real-time<br />

filters separate real-time specifications from methods, the real-time specification<br />

anomalies are eliminated [Aksit94]. (this subject is not addressed by this thesis)<br />

• Inheritance versus synchronization;<br />

A wait filter in combination with conditions can be applied to specify synchronization<br />

con<strong>st</strong>raints. By using wait filters, the synchronization inheritance anomalies are<br />

avoided [Bergmans94a]. (refer to section 9.6.4, page 70)<br />

• Multiple interfaces (views);<br />

Multiple interfaces can be specified by using a dispatch filter or error filter with<br />

conditions based on the context. These conditions are used to differentiate between<br />

(groups of) clients [Aksit92b]. (refer to section 9.6.1, page 70 and section 9.6.2,<br />

page 70)<br />

• Part-of versus inheritance;<br />

This problem can be avoided by using a dispatch filter and an internal as superclass.<br />

The composition filters object model does not make a di<strong>st</strong>inction between part-of and<br />

inheritance relation: conceptually there is an inheritance relation when an internal<br />

object is the target object of a dispatch filter [Aksit88][Aksit92b]. (refer to<br />

section 6.1.1, page 39)<br />

• Lack of reflection;<br />

Reflection on messages and the communication between objects is supported by the<br />

meta filter and ab<strong>st</strong>ract communication types [Aksit93]. (refer to section 9.6.5, page 71<br />

and section 10.4, page 77)<br />

• Sharing behavior with <strong>st</strong>ate;<br />

This problem can be solved by applying a dispatch filter which delegates a message to<br />

an object external to the receiver. As this object is not encapsulated by the receiver, it<br />

can be shared by several other objects. Since this shared object is an in<strong>st</strong>ance of some<br />

class, it provides common behavior while it encapsulates the shared <strong>st</strong>ate<br />

[Aksit88][Aksit92b]. (refer to section 3.3, page 25 and section 9.6.1, page 70)<br />

• Unmatched sy<strong>st</strong>em functionalities;<br />

Ab<strong>st</strong>ract communication type objects, together with meta filters can be used to<br />

implement extensible sy<strong>st</strong>em functionalities [Aksit93]. (refer to section 9.6.5, page 71<br />

and section 10.4, page 77)<br />

1.3 The pa<strong>st</strong>, present, and future<br />

The composition filters object model evolved from earlier versions of the programming<br />

language <<strong>st</strong>rong>Sina</<strong>st</strong>rong>. The <<strong>st</strong>rong>Sina</<strong>st</strong>rong> language was named after the medieval philosopher, scienti<strong>st</strong> and<br />

physician Ibn <<strong>st</strong>rong>Sina</<strong>st</strong>rong> who is also known under the Latin name of Avicenna.<br />

Chapter 1: Introduction


The fir<strong>st</strong> version of <<strong>st</strong>rong>Sina</<strong>st</strong>rong> was developed around 1985 by Mehmet Aksit when he was<br />

working at the Research department of Océ Nederland B.V. A preliminary version of the<br />

composition filters concept was called semantic network. This semantic network<br />

con<strong>st</strong>ruction served as an extension to objects (classes, messages, in<strong>st</strong>ances) which could<br />

be configured to form other objects, such as classes from which in<strong>st</strong>ances could be created.<br />

An object manager took care of synchronization and message processing of an object. The<br />

semantic network con<strong>st</strong>ruction already could express the key concepts of delegation,<br />

reflection, and synchronization.<br />

In 1987, when Mehmet Aksit moved to the University of <strong>Twente</strong>, the semantic network<br />

concept evolved to interface predicates which describe which messages an object is able<br />

to handle. In the second version of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>, the functionality of the object manager was<br />

reduced, and the possibility to configure objects into classes was abolished. To ab<strong>st</strong>ract<br />

communications among objects, the notion of ab<strong>st</strong>ract communication type was<br />

introduced, while atomic delegations made it possible to describe transactions [Aksit89].<br />

In this period, Anand Tripathi of the University of Minnesota contributed to the language<br />

design, while Hans Bank, Ruud Nijhuis, Jan-Willem Dijk<strong>st</strong>ra, Willem Veldkamp, Gerard<br />

van Wageningen, and Nini Poortenga were involved as <strong>st</strong>udents.<br />

The TRESE project was e<strong>st</strong>ablished by Mehmet Aksit in the beginning of 1991. As result<br />

of ongoing research, the foundation for the present day composition filters object model<br />

was defined in the same period. The interface predicates of the prior version were replaced<br />

by the dispatch filter and the wait filter took over the synchronization functions of the<br />

object manager. Message reflection and real-time specifications are handled by the meta<br />

filter and the real-time filter, respectively. The composition filters object model turned to<br />

be the major focus of attention of the TRESE project while the language <<strong>st</strong>rong>Sina</<strong>st</strong>rong> became an<br />

expressive in<strong>st</strong>rument for it. As a result, the third version of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>, <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> version 3.00 ,<br />

integrates the composition filters object model.<br />

Contributions to the composition filters object model and the <<strong>st</strong>rong>Sina</<strong>st</strong>rong> language were made by<br />

the project members Lodewijk Bergmans, Richard van de Stadt, Jan Bosch, Ken Wakita,<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>n Vural and Sander Pool, and the <strong>st</strong>udents Koen Le<strong>st</strong>erhuis, William van der Sterren,<br />

Piet Koopmans, Coen Stuurman, Maurice Glandrup, John Mordhor<strong>st</strong>, and Wietze van<br />

Dijk.<br />

The composition filters object model already has been applied in several projects. These<br />

include an atomic transactions framework [Tekinerdogan94], a process programming<br />

framework [Algra94], an image algebra framework [Vuij<strong>st</strong>94], and a fuzzy-logic<br />

reasoning framework [Marcelloni95].<br />

Currently, the TRESE project is extending the conventional object-oriented languages<br />

Smalltalk [Goldberg83][Goldberg89] and C++ [Ellis90] with composition filters. This is<br />

possible because the composition filters object model is a modular extension to the basic<br />

object-oriented model. Further, some practical improvements to the syntax and semantics<br />

of composition filters have been introduced, while research continues on new filter types,<br />

such as the active filter, the multiple-dispatch filter, the atomic filter, and the sub<strong>st</strong>itution<br />

filter.<br />

1.4 Problem <strong>st</strong>atement and approach of this thesis<br />

As described in the former sections, <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> is a concurrent object-oriented programming<br />

language which incorporates the composition filters object model. This model has a<br />

number of unique features which require a different approach to implement it.<br />

The major difference with conventional object oriented languages is that the composition<br />

filters of an object decide how the object handles a received or sent message. In<br />

conventional object oriented languages such as Smalltalk [Goldberg83][Goldberg89] and<br />

C++ [Ellis90] the method lookup process to search for a method corresponding to the<br />

received message.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

9


10<br />

A message that is sent or received by an object is offered to the filters to be filtered. In<br />

order to decide what the filter has to do with the message, it mu<strong>st</strong> be able to reflect on the<br />

message (sy<strong>st</strong>em level reflection). Because conditions, which represent the <strong>st</strong>ate of an<br />

object, can influence this decision, the filtering process has a dynamic nature. Message<br />

reification and dereification allow an ACT object to reflect on a message (application level<br />

reflection). Concurrency and synchronization are also important features of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

language.<br />

Problem <strong>st</strong>atement The aim of this thesis is to define the syntax and the semantics of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language, and<br />

to inve<strong>st</strong>igate how <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> can be implemented. The third goal is to evaluate the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

language with respect to the syntax and semantics of composition filters.<br />

One of our concerns is to focus on the intere<strong>st</strong>ing aspects of the composition filters object<br />

model, such as filters, message reification and dereification, concurrency and<br />

synchronization. We want to develop an implementation that demon<strong>st</strong>rates the benefits of<br />

the composition filters object model above the conventional object-oriented model. We<br />

therefore do not consider performance of the implementation of the uttermo<strong>st</strong> importance.<br />

Although <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> is a typed language, this thesis does not address type-checking either.<br />

Approach Fir<strong>st</strong> of all, the syntax and semantics of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language is defined in an informal way.<br />

Several examples will be used to demon<strong>st</strong>rate them. The <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> definition extensively<br />

describes the filtering process, and the message passing semantics including message<br />

reification and dereification. We introduce an new message dereification method which<br />

allows an ACT to regain control over a reified message as soon as this message receives a<br />

reply object.<br />

Secondly, we describe an implementation model for the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language. This model is<br />

composed of the execution model and the translation model. The execution model defines<br />

the run-time aspects and addresses the representation of messages, the filtering process,<br />

concurrency and synchronization. The translation model defines how <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> can be<br />

mapped to the target language, which is Smalltalk in this case. The implementation model<br />

will be used to implement <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> .<br />

The implementation provides a programming environment, which includes a user interface<br />

that allows the user to edit, compile and execute a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> application, a compiler that<br />

translates <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> source code to Smalltalk, and a kernel for run-time support. The objectoriented<br />

language Smalltalk [Goldberg83], and the Objectworks\Smalltalk development<br />

environment [ParcPlace92a] are used to implement <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> .<br />

Finally, the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language and its implementation are evaluated, and sugge<strong>st</strong>ions are<br />

made for enhancements.<br />

1.5 Outline of this thesis<br />

This thesis has been divided into five parts. The fir<strong>st</strong> part contains this introduction which<br />

you are reading at this very moment.<br />

In part II, ‘Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language’, we define the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language. This part is<br />

also included in [Koopmans95]. The fir<strong>st</strong> chapter in this part, chapter 2, describes the<br />

composition filters object model in full detail, gives an overview of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language,<br />

and outlines the re<strong>st</strong> of this part.<br />

The implementation of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> is described in part III, ‘Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

language’. Chapter 11 discusses the implementation problems and gives an outline of the<br />

approach. The following chapter defines the execution model which addresses the<br />

representation of messages, the filtering process, message reification and dereification, and<br />

concurrency and synchronization. Chapter 13 defines the translation model which shows<br />

how <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> entities are mapped to Smalltalk. Finally, chapter 14 describes the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

programming environment.<br />

Chapter 1: Introduction


In part IV, ‘Evaluation and Conclusions’, we evaluate the language and the<br />

implementation, summarize the work presented in this thesis, and give directions for future<br />

work.<br />

The final part of this thesis, part V, contains relevant information, including the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

syntax.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

11


12<br />

Chapter 1: Introduction


PART<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong><br />

ii Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language


2 Language survey<br />

In this chapter, we explain the composition filters object model in short and give an<br />

overview of the language elements of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>. The la<strong>st</strong> section shows how to read the re<strong>st</strong><br />

of this part of the thesis.<br />

2.1 The composition filters object model<br />

The composition filters object model is class based: for an application consi<strong>st</strong>ing of a<br />

number of objects, all objects with common characteri<strong>st</strong>ics are in<strong>st</strong>ances of the same class.<br />

Objects are only specified on class level; this supports the creation of multiple in<strong>st</strong>ances<br />

and reuse through the inheritance mechanism ([Bergmans94a][Bergmans94b]).<br />

FIGURE 2-1 An object composed of an interface layer and an inner object<br />

implementation part<br />

interface part<br />

As can be seen in figure 2-1, an object in the composition filters object model is composed<br />

of an inner object and an interface layer. The inner object implements the object’s specific<br />

behavior. The interface layer encloses the inner object and manages incoming and<br />

outgoing messages.<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> the interface layer is defined by the interface part (section 2.2.2), and the inner<br />

object by the implementation part (section 2.2.1). The coming section describes the inner<br />

object, while section 2.1.2 covers the complete composition filters object.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

received messages<br />

sent messages<br />

interface layer<br />

inner object<br />

15


16<br />

2.1.1 The inner object<br />

The inner object implements an object’s specific behavior and holds its <strong>st</strong>ate. As pictured<br />

in figure 2-2, the inner object contains three main components: methods, conditions and<br />

in<strong>st</strong>ance variables. The names of the methods and the conditions are visible on the<br />

encapsulating boundary of the inner object, whereas the in<strong>st</strong>ance variables are fully<br />

encapsulated by it. The inner object is embodied in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> by the implementation part and<br />

is explained in section 2.2.2.<br />

FIGURE 2-2 The inner object with in<strong>st</strong>ance variables, methods and conditions<br />

conditions<br />

in<strong>st</strong>ance<br />

variables<br />

In<strong>st</strong>ance variables An in<strong>st</strong>ance variable holds the <strong>st</strong>ate of an object. An in<strong>st</strong>ance variable is an in<strong>st</strong>ance of a<br />

specific class which is created when the inner object is created.<br />

Methods The behavior of an object is implemented by its methods. A method defines a number of<br />

actions that are performed in reaction to the invocation of the method.<br />

Conditions A condition provides information about the current <strong>st</strong>ate of the object. It is a special kind<br />

of method that takes no parameters and returns a boolean result.<br />

2.1.2 The composition filters object<br />

Figure 2-3 shows the inner object being surrounded by an interface layer. The following<br />

components can be di<strong>st</strong>inguished in the interface layer: internals, externals, input filters<br />

and output filters. The interface layer is embodied in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> by the interface part and is<br />

explained in section 2.2.1.<br />

Internals Internals are fully encapsulated objects and are used to compose the behavior of the<br />

composition filters object: a received message could be delegated to an internal object<br />

in<strong>st</strong>ead of the inner object, for in<strong>st</strong>ance.<br />

Externals External objects are objects that exi<strong>st</strong> outside the composition filters object, such as global<br />

objects. They can be used to share data among objects. An example of this is a department<br />

secretary which is an external for all the managers of this department. When a manager is<br />

asked to make an appointment, he delegates this reque<strong>st</strong> to the secretary which maintains<br />

his agenda. Similarly to internals, they are also used to compose the behavior of the<br />

composition filters object.<br />

In figure 2-3 the interior <strong>st</strong>ructure of the internal and external objects and in<strong>st</strong>ance<br />

variables is not shown, but they are composition filters objects as well, having an inner<br />

object and an interface layer.<br />

Input filters The input filters handle messages that are received by the object. One type of filter that can<br />

be part of the input filters is the so called dispatch filter which can either invoke a method<br />

of the inner object, or offer the message to the input filters of an internal or external object.<br />

Output filters The output filters handle messages that are sent by the object. A so called send filter<br />

delivers the message at the input filters of the receiver of the message.<br />

Chapter 2: Language survey<br />

methods


Sending a message When an object (the sender) sends a message to another object (the receiver), the message,<br />

in general, is filtered by the output filters of the sender, and then by the input filters of the<br />

receiver. Every filter decides what to do with the message. Eventually, there is some filter<br />

(a dispatch filter) that invokes a designated method. Hence, filtering a message can be<br />

thought of as the method lookup.<br />

FIGURE 2-3 The composition filters object<br />

interface layer<br />

internals<br />

inner object<br />

Filtering a message When a filter filters a message, the filter either accepts or rejects the message. When a<br />

dispatch filter accepts a message, it invokes a method or offers the message to the input<br />

filters of an internal or external. A rejected message continues in the following filter.<br />

Similarly, a send filter delivers the message to the input filters of the receiver when it<br />

accepts a message, and offers it to the next filter when it rejects a message.<br />

Filtertypes Filtertypes that can appear in the input filters or output filters group include the<br />

aforementioned dispatch filter and send filter, and further the wait filter, the error filter and<br />

the meta filter. The wait filter can be used for inter and intra object synchronization: when<br />

it rejects a message, the execution of the message is suspended. The execution resumes<br />

when a certain condition is met, causing the message to be filtered by the following filter.<br />

The error filter raises an error when it rejects a message. The meta filter is able to reflect on<br />

message communication between objects. When a message is accepted by this filter, it is<br />

offered to another object. This object is thus able to reflect on the message, i.e. the<br />

communication between two objects.<br />

In the class interface part, the input filters and output filters can be declared containing an<br />

arbitrary set of those filters. In this way, an object’s behavior can be composed by selecting<br />

the appropriate combination of filters.<br />

2.2 A composition filters object in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong><br />

As mentioned in the previous section, the interface layer of a composition filters object is<br />

realized in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> by the interface part of a class definition, and the inner object is realized<br />

by the implementation part of a class definition. This section describes the <strong>st</strong>ructure of<br />

these parts by using class Stack as an illu<strong>st</strong>rative example. Class Stack provides operations<br />

like push, pop, top and size. An error is raised when an element is popped from an empty<br />

Stack, or when the top element is reque<strong>st</strong>ed of an empty Stack.<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> an application can be <strong>st</strong>arted by using the main method. This is demon<strong>st</strong>rated in<br />

section 2.2.3.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

received messages<br />

sent messages<br />

input filters<br />

externals<br />

output filters<br />

17


18<br />

2.2.1 The interface part<br />

Example 2-1A shows the definition of the interface part in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>. The name of the class,<br />

Stack, is placed between the keywords class and interface. We can recognize the<br />

components from figure 2-3: they are marked by the respective keywords.<br />

The ordering of the keyword sections are as indicated. When the class has no components<br />

defined for a section, the keyword can be omitted. The minimum interface of a class is thus<br />

comprised of the keyword class, its name and the keywords interface and end.<br />

Comment The section <strong>st</strong>arting with the keyword comment defines the comment of the class<br />

interface. This kind of comment can only appear at this specific location. A comment<br />

<strong>st</strong>arting with // can appear everywhere and extends to the end of the line.<br />

Externals Externals, and also internals, are declared as a named in<strong>st</strong>ance of some class. Since the<br />

external objects lay outside the object, it is checked whether they exi<strong>st</strong> and where they are<br />

located when the object is created. Class Stack has no externals declared.<br />

Internals When an in<strong>st</strong>ance of the class is created, its internals are created. Since every internal is<br />

declared as an in<strong>st</strong>ance of some class, their internals, if there are any, are created, and so<br />

on.<br />

The internal default of class Stack is declared as an in<strong>st</strong>ance of the class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object. This<br />

class provides default operations, such as printing, te<strong>st</strong>ing and comparison.<br />

EXAMPLE 2-1A class Stack interface<br />

comment<br />

’This class represents a <strong>st</strong>ack containing elements of arbitrary type.’;<br />

externals<br />

// This class has no externals, but they could be declared as<br />

// anExt : ClassName;<br />

internals<br />

default : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object;<br />

conditions<br />

<strong>st</strong>ackNotEmpty;<br />

methods<br />

push(object : Any) returns nil; // Stores the argument object.<br />

pop returns nil; // Removes the top element<br />

top returns Any; // Answers the top element<br />

size returns SmallInteger; // Answers the number of elements<br />

inputfilters<br />

<strong>st</strong>ackEmpty : Error = { <strong>st</strong>ackNotEmpty => {pop, top}, true ~> {pop, top} };<br />

invoke : Dispatch = { true=>inner.*, true=>default.* };<br />

outputfilters<br />

send : Send = { true=>* };<br />

end; // Stack interface<br />

Conditions In the conditions section, the names of the conditions are specified. Conditions can be<br />

used in a filter to te<strong>st</strong> whether to accept or to reject a message. The class Stack has only<br />

one condition, <strong>st</strong>ackNotEmpty, which reflects whether the <strong>st</strong>ack is empty or not.<br />

Methods The methods section defines methods which are available to other objects. The<br />

parameters and the type of the value returned by these interface methods are specified.<br />

Apart from interface methods, a class can have private methods which can only be<br />

accessed by the class itself. Private methods are declared in the implementation part.<br />

Input filters In the inputfilters section, an arbitrary number of filters are declared. A filter declaration<br />

defines the name of the filter, the filtertype and the filterinitializer.<br />

The filter initializer, the part between the curly braces {}, specifies which messages under<br />

which conditions are accepted by the filter. The filter initializer is comprised of a number<br />

Chapter 2: Language survey


of filter elements, each of which specifies a condition and a set of messages to be accepted.<br />

The filter elements are evaluated from left to right: if the message is not accepted by one<br />

filter element, for in<strong>st</strong>ance when the condition is invalid, then the message could <strong>st</strong>ill be<br />

accepted by a following filter element.<br />

For example, the initializer of Stack’s fir<strong>st</strong> input filter, the error filter named <strong>st</strong>ackEmpty,<br />

specifies that the filter accepts messages with the selector pop or top when the <strong>st</strong>ack is not<br />

empty. This is expressed by the fir<strong>st</strong> filter element <strong>st</strong>ackNotEmpty=>{pop,top}. It could be<br />

read as “if <strong>st</strong>ackNotEmpty then accept a message with (pop or top)”.<br />

The second filter element true~>{pop,top} could be interpreted as “if true then accept a<br />

message not with (pop or top)”, which is the same as “accept a message without pop and<br />

without top”. This filter element specifies that the filter further accepts messages with any<br />

selector except pop and top. As a result, the error filter rejects messages with selector pop<br />

or top when the <strong>st</strong>ack is empty, causing it to generate an error, and accept messages<br />

otherwise.<br />

Messages that have passed the error filter, are filtered by the following filter, the dispatch<br />

filter invoke. This filter accepts messages that are supported by the inner object (the filter<br />

element true=>inner.*) or that are supported by the internal default (true=>default.*). By<br />

definition, the messages supported by the inner object are the interface methods, which are<br />

push, pop, top and size in this case. When the dispatch filter accepts a message, it invokes<br />

the corresponding method of inner, or offers the message to the object default. This object<br />

filters the message and eventually invokes a method. Suppose that the default object also<br />

supports a method size, then, by the evaluation of filter elements from left to right, <strong>st</strong>ill the<br />

size method of inner is invoked.<br />

From this we can conclude that an in<strong>st</strong>ance of class Stack supports the messages push,<br />

pop, top, size and all the messages which are defined by class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object. The message<br />

pop or top sent to an empty <strong>st</strong>ack generates an error.<br />

Output filters Like the former section, an arbitrary number of filters can be declared in the outputfilters<br />

section. The send filter send sends all messages (the filterelement true=>*) sent by a Stack<br />

in<strong>st</strong>ance to the receiver of the message.<br />

2.2.2 The implementation part<br />

The implementation part of a class in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> is shown in example 2-1B. The name of the<br />

class is repeated between the keywords class and implementation. The implementation<br />

part has sections which respectively define a comment, the in<strong>st</strong>ance variables, the<br />

implementation of the conditions, an initial method and the implementations of private and<br />

interface methods. Again, when the class has no components defined for one of these<br />

sections, the corresponding keyword can be omitted.<br />

Comment A comment section in the implementation part can appear ju<strong>st</strong> after implementation and<br />

further in conditions and methods.<br />

In<strong>st</strong>ance variables The in<strong>st</strong>ance variables of the class are defined in the in<strong>st</strong>vars section. Like internals and<br />

externals, they are declared as a named in<strong>st</strong>ance of some class. The in<strong>st</strong>ance variables of<br />

an object are created after the internals have been created. The in<strong>st</strong>ance variable <strong>st</strong>orage<br />

contains the elements of the <strong>st</strong>ack, while the SmallInteger <strong>st</strong>ackPtr points to the la<strong>st</strong> used<br />

location in this Array.<br />

Conditions The implementation of the conditions are defined in the conditions section. A condition<br />

mu<strong>st</strong> return a boolean result. In the condition <strong>st</strong>ackNotEmpty, the <strong>st</strong>ate of the <strong>st</strong>ack is<br />

determined with the expression <strong>st</strong>ackPtr > 0.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

19


20<br />

Initial method The initial method can be used to initialize the in<strong>st</strong>ance. It is invoked at in<strong>st</strong>ance creation<br />

time, after the internals and in<strong>st</strong>ance variables have been created. The class Stack uses it to<br />

initialize the <strong>st</strong>ackPtr.<br />

Methods In the methods section, the implementation of the interface methods are defined.<br />

Implementations of private methods can also be found here.<br />

EXAMPLE 2-1B class Stack implementation<br />

comment<br />

’The in<strong>st</strong>ance variable ”<strong>st</strong>ackPtr” points to the la<strong>st</strong> used location of the<br />

<strong>st</strong>ack. The in<strong>st</strong>ance variable ”<strong>st</strong>orage” holds the elements of the <strong>st</strong>ack’;<br />

in<strong>st</strong>vars<br />

<strong>st</strong>ackPtr : SmallInteger;<br />

<strong>st</strong>orage : Array;<br />

conditions<br />

<strong>st</strong>ackNotEmpty<br />

comment ’This <strong>st</strong>ate is true when the <strong>st</strong>ack contains elements’;<br />

begin return <strong>st</strong>ackPtr > 0; end;<br />

initial<br />

comment ’Start with an empty <strong>st</strong>ack’;<br />

begin <strong>st</strong>ackPtr := 0; end;<br />

methods<br />

push(object : Any)<br />

comment ’Pushes the argument object onto the <strong>st</strong>ack’;<br />

begin<br />

<strong>st</strong>ackPtr := <strong>st</strong>ackPtr + 1;<br />

<strong>st</strong>orage.at:put:(<strong>st</strong>ackPtr, object)<br />

end;<br />

top<br />

comment ’Answers the top element of the <strong>st</strong>ack’;<br />

temps object : Any;<br />

begin<br />

object := <strong>st</strong>orage.at:(<strong>st</strong>ackPtr);<br />

return object<br />

end;<br />

pop<br />

comment ’Removes the top element from the <strong>st</strong>ack’;<br />

begin<br />

<strong>st</strong>ackPtr := <strong>st</strong>ackPtr - 1;<br />

end;<br />

size<br />

comment ’Answers the number of elements on the <strong>st</strong>ack’;<br />

begin return <strong>st</strong>ackPtr<br />

end;<br />

end; // Stack implementation<br />

Local variables Local variables of a method, and also condition, are defined after the keyword temps. The<br />

method top, for in<strong>st</strong>ance, uses a local variable named object to retrieve the top element of<br />

the <strong>st</strong>ack.<br />

Statements The body of a method, surrounded by begin and end, can contain any number of<br />

<strong>st</strong>atements and expressions. An assignment <strong>st</strong>atement <strong>st</strong>ores a value —an object— in a<br />

variable. <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> further defines <strong>st</strong>atements like if-then-else, a while-loop and a for-loop.<br />

A value can be returned from a method, but also from a condition, by using the return<br />

<strong>st</strong>atement. The condition <strong>st</strong>ackNotEmpty and the methods top and size demon<strong>st</strong>rate this.<br />

Expressions There are two types of expressions in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>: an operator expression, like <strong>st</strong>ackPtr + 1, and<br />

a message expression, like <strong>st</strong>orage.at:(<strong>st</strong>ackPtr) in which the message at: with argument<br />

<strong>st</strong>ackPtr is sent to the object <strong>st</strong>orage. In fact, an operator expression is a shorthand notation<br />

for a message expression. The compiler converts every operator expression to an<br />

equivalent message expression: <strong>st</strong>ackPtr + 1 is replaced by <strong>st</strong>ackPtr.plus(1).<br />

Chapter 2: Language survey


2.2.3 The main method<br />

The main method can be used <strong>st</strong>art an application. In general, the main method is very<br />

small, but you can use it to te<strong>st</strong> newly defined classes. Example 2-2 shows this in which the<br />

class Stack from example 2-1 is applied and te<strong>st</strong>ed.<br />

EXAMPLE 2-2 main<br />

comment ’Application of class Stack’;<br />

externals<br />

Transcript : TextCollector;<br />

temps<br />

<strong>st</strong>ack : Stack;<br />

begin<br />

<strong>st</strong>ack.push(’1<strong>st</strong> element’);<br />

<strong>st</strong>ack.push(2.0d0);<br />

<strong>st</strong>ack.push(’3rd element’);<br />

while <strong>st</strong>ack.size > 0<br />

begin<br />

Transcript.print:(<strong>st</strong>ack.top);<br />

Transcript.cr;<br />

<strong>st</strong>ack.pop<br />

end;<br />

Transcript.flush<br />

end<br />

The main method has the same <strong>st</strong>ructure as a method implementation. The only difference<br />

is that global objects that are referred to by main mu<strong>st</strong> be declared in the externals section.<br />

The external Transcript in example 2-2 is a global Smalltalk object which can be used to<br />

display messages on. The variable <strong>st</strong>ack is local to main and has been declared in the<br />

temps section. The body shows that the <strong>st</strong>ack is filled with three elements. Then, they are<br />

displayed on the Transcript and removed from the <strong>st</strong>ack in the while-loop.<br />

2.3 Forthcoming chapters<br />

The re<strong>st</strong> of this part of the thesis discusses the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> language in more detail.<br />

2.3.1 Syntax<br />

Appendix C contains the complete syntax of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> language. In following chapters,<br />

we will present parts of the the syntax when we explain certain elements of the language.<br />

The production for the conditional <strong>st</strong>atement, for example, is denoted as<br />

conditionalStatement ::=<br />

if expression<br />

then <strong>st</strong>atements<br />

( else <strong>st</strong>atements )?<br />

end<br />

A production consi<strong>st</strong>s of a nonterminal, called the left side of the production, a ::=<br />

symbol, and a sequence of terminals, nonterminals and metasymbols, called the right side<br />

of the production. Terminals are symbols which are shown in boldface font, like the<br />

semicolon ; and the keywords if, then, else and end. For every nonterminal, shown in<br />

normal font, there is a production defined. Tokens on the right side of the production can<br />

be grouped by the metasymbols ( and ). A token or a token group followed by the<br />

metasymbol ? defines that the token, c.q. group is optional. The metasymbol * defines a<br />

sequence of zero or more occurrences of the token or group. Finally, the metasymbol |<br />

between token sequences specifies a choice between them.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

21


22<br />

2.3.2 Terminology<br />

In the following chapters, we often refer to the term fir<strong>st</strong>-class object and the terms owner,<br />

owning object or owning class. They are defined here.<br />

Fir<strong>st</strong>-class object According to [Wegner87], fir<strong>st</strong>-class objects can “be assigned to variables, be passed as<br />

parameters and be components of <strong>st</strong>ructures”. To put it in another way: a fir<strong>st</strong>-class object<br />

can be <strong>st</strong>ored somewhere, while a non fir<strong>st</strong>-class object is only available during execution<br />

and cannot be <strong>st</strong>ored. An active message, an objectmanager and a filter are examples of<br />

non fir<strong>st</strong>-class objects. Some non fir<strong>st</strong>-class objects can be accessed, like fir<strong>st</strong>-class objects,<br />

by sending a message to it. These kinds of objects include an active message and the object<br />

manager, because they are represented by the pseudo variables message, ^self and ^server.<br />

A filter on the other hand, cannot be accessed by sending a message to it.<br />

Owner The owning class or owning object of an entity (for in<strong>st</strong>ance, a filter or an internal) is the<br />

class, cq. the particular in<strong>st</strong>ance of the class, in which the entity was defined. By the term<br />

owner we mean the owning class or owning object, depending on the context. We can<br />

speak of the owner of an internal, a filter, a method, etc. For in<strong>st</strong>ance, the owner of the<br />

error filter <strong>st</strong>ackEmpty in example 2-1A is the class Stack. In example 2-2, its owning<br />

object would be the object <strong>st</strong>ack.<br />

2.3.3 Structure of a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> program<br />

A <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> program consi<strong>st</strong>s of a single main method, or one or more class declarations,<br />

optionally followed by a main method. The syntax is thus:<br />

program ::=<br />

main | classDeclaration ( classDeclaration )* main?<br />

2.3.4 Where to find what<br />

Each of the following chapters addresses a specific topic of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>. The overview below<br />

shows the subjects covered by each chapter.<br />

Chapter 3 – Basic language elements<br />

literals: characters, <strong>st</strong>rings, numbers, nil, true, false; variables: local<br />

variables, method parameters, in<strong>st</strong>ance variables, internals, externals,<br />

class parameters, global externals; pseudo variables: inner, self, server,<br />

sender, message, ^self, ^server;<br />

Chapter 4 – Expressions<br />

message expression; operator expression;<br />

Chapter 5 – Control <strong>st</strong>ructures<br />

conditional <strong>st</strong>atement; for <strong>st</strong>atement; while <strong>st</strong>atement;<br />

Chapter 6 – Classes<br />

interface part; implementation part; in<strong>st</strong>ance creation; object manager:<br />

class ObjectManager; default behavior: class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object;<br />

Chapter 7 – Methods<br />

interface method; private method; initial method; main method;<br />

returning a value; normal vs. early return; <strong>st</strong>atements;<br />

Chapter 8 – Conditions<br />

reused condition; local condition;<br />

Chapter 9 – Filters<br />

input filters; output filters; reused filter; local filter; filtering a message;<br />

signature of an object; filtertypes: dispatch filter; error filter, send filter,<br />

wait filter, meta filter;<br />

Chapter 10 – Message passing semantics<br />

sending a message; creating concurrency; thread; message reification;<br />

message dereification; active message: pseudovariable message, class<br />

ActiveMessage; reified message: class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message;<br />

Chapter 2: Language survey


3 Basic language<br />

elements<br />

This chapter describes the basic language elements in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>. The fir<strong>st</strong> section discusses<br />

the comment. Section 3.2 defines the literal con<strong>st</strong>ants, such as characters, <strong>st</strong>rings, numbers,<br />

and the special literals nil, true and false. The following section describes variables and<br />

their declaration, while section 3.4 discusses the global externals. The la<strong>st</strong> section defines<br />

the various pseudo variables.<br />

3.1 Comment<br />

Two forms of comment are allowed in a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>: a one-line comment and a comment that<br />

begins with the keyword comment.<br />

The one-line comment <strong>st</strong>arts with two slash-characters (//) and extends to the re<strong>st</strong> of the<br />

line. It can contain any character except the newline character, of course.<br />

The second form of comment consi<strong>st</strong>s of the keyword comment followed by a <strong>st</strong>ring<br />

literal and a closing semicolon character. The <strong>st</strong>ring literal, as we will see in section 3.2.2,<br />

can contain any character including a newline character, and therefore this type of<br />

comment can extend over several lines. This type of comment can only appear at fixed<br />

locations:<br />

• the interface part of a class (refer to section 6.1.1);<br />

• the implementation part of a class (section 6.1.2);<br />

• the method implementation (sections 7.1-7.3);<br />

• the main method implementation (section 7.4).<br />

• the condition implementation (section 8.2);<br />

The example below shows the use of both an interface comment and a one-line comment<br />

class Stack interface<br />

comment ’You should describe here the function<br />

and behavior of class Stack’;<br />

...<br />

end; // Stack interface<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

23


24<br />

3.2 Literal con<strong>st</strong>ants<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> provides three types of literal con<strong>st</strong>ants:<br />

• characters;<br />

• <strong>st</strong>rings;<br />

• numbers.<br />

In addition, three special con<strong>st</strong>ants are defined: nil, true and false.<br />

3.2.1 Characters<br />

A character literal is made up of an initial $-character followed by one character which can<br />

be any character including a newline, a tab or a space character. The following literals are<br />

all examples of character literals:<br />

$z<br />

$$<br />

$P<br />

$3<br />

$<br />

$.<br />

Every character literal is an in<strong>st</strong>ance of class Character.<br />

3.2.2 Strings<br />

A <strong>st</strong>ring literal is enclosed in single quote characters (’) and can contain any number of<br />

characters which can be any character including a newline, a tab or a space character. To<br />

include the single quote character itself, it mu<strong>st</strong> be preceded with a single quote character.<br />

The following four <strong>st</strong>ring literals illu<strong>st</strong>rate this.<br />

’To be or not to be?’ // a <strong>st</strong>ring with several characters<br />

’A tab and a newline<br />

character can be included’ // a <strong>st</strong>ring containing a tab and a newline.<br />

’’ // an empty <strong>st</strong>ring<br />

’’’’ // a <strong>st</strong>ring containing only one quote character<br />

Every <strong>st</strong>ring literal is an in<strong>st</strong>ance of class String.<br />

3.2.3 Numbers<br />

There are two types of number literals: integer literals which do not have a decimal point<br />

embedded in them, and floating point literals which do. A negative number is represented,<br />

as usual, with a preceding minus sign. There mu<strong>st</strong> be no space between the minus sign and<br />

the literal, since the minus sign would otherwise be interpreted as the negation operator<br />

(see Section 4.3 on page 33).<br />

1496.0 // positive floating point number 1496<br />

-1496 // negative integer number -1496<br />

- 1496 // negated positive integer number 1496<br />

- -1496 // negated negative integer number -1496<br />

Number literals can also be expressed in scientific notation by including an exponential<br />

part. The exponential part is composed of a preceding “e” or “d” and the exponent in<br />

decimal. The exponential part <strong>st</strong>arting with an “e” can be used both with an integer and a<br />

floating point literal, whereas the exponential part <strong>st</strong>arting with an “d” can be used only<br />

with a floating point literal. A floating point literal having an exponential part that <strong>st</strong>arts<br />

with a “d” represents a double-precision number. A floating point literal without an<br />

exponential part or with one that <strong>st</strong>arts with an “e” represents a single-precision number.<br />

Chapter 3: Basic language elements


Variables are references<br />

to objects<br />

13e2 // integer number 1300<br />

-13.0e2 // single-precision floating point number -1300<br />

-13.0d2 // double-precision floating point number -1300<br />

Integer literals are in<strong>st</strong>ances of class SmallInteger. Every floating point literal having an<br />

exponential part which <strong>st</strong>arts with a “d” is an in<strong>st</strong>ance of class Double. A floating point<br />

literal without an exponential part or with one that <strong>st</strong>arts with an “e” is an in<strong>st</strong>ance of class<br />

Float.<br />

-1496 // a SmallInteger<br />

1496.0 // a Float<br />

13e2 // a SmallInteger<br />

-13.0e2 // a Float<br />

-13.0d2 // a Double<br />

0.0 // the Float 0.0<br />

0.0e0 // another representation for the Float 0.0<br />

0.0d0 // the Double 0.0<br />

3.2.4 The con<strong>st</strong>ants nil, true and false<br />

The object nil denotes an undefined object. The nil object is the sole in<strong>st</strong>ance of class<br />

UndefinedObject.<br />

The boolean con<strong>st</strong>ants true and false are the sole in<strong>st</strong>ances of classes True and False,<br />

respectively, which are both subclasses of class Boolean.<br />

3.3 Variables<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> provides six types of variables:<br />

• local variables of a method, a condition or main. They are declared in the temps<br />

section of the method, condition or main respectively;<br />

• parameters of a method. They are declared in the header of the method;<br />

• in<strong>st</strong>ance variables of an object. They are declared in the in<strong>st</strong>vars section of the<br />

implementation part of a class;<br />

• internal objects. They are declared in the internals section of the interface of a class. A<br />

class can uses an internal to compose its behavior from;<br />

• external objects. They are declared in the externals section of the interface of a class.<br />

Externals can be used to compose the behavior from and to share data among objects.<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> version 3.00, externals can only be global externals (see section 3.4) <strong>st</strong>ored<br />

in the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Repository. Future versions will implement full scope rules which allow<br />

externals also to be internal variables, in<strong>st</strong>ance variables, or local variables of an<br />

encapsulating object;<br />

• parameters of a class which are used to initialize an in<strong>st</strong>ance of a class. A class<br />

parameter behaves like an in<strong>st</strong>ance variable of a class. Class parameters are declared in<br />

the interface part of a class.<br />

Variables mu<strong>st</strong> have been declared before they can be used (sections 3.3.1 and 3.3.2).<br />

Once a variable has been declared, it has an initial value –an object– which is assigned<br />

automatically or comes from the environment (3.3.3). The value of a variable can be<br />

changed by assigning a new object to it (3.3.4). The nil object can be assigned to a variable<br />

to indicate that its value is undefined.<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>, every variable is a reference to an object. As a consequence, method and class<br />

parameters are passed by reference too. When an object is not referred to by other objects,<br />

its memory is reclaimed automatically.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

25


26<br />

The consequence of variables being object references is that when one variable is assigned<br />

to another variable, they both refer to the same object.<br />

main<br />

externals Transcript : TextCollector;<br />

temps john, mary : Person;<br />

begin<br />

john.setName(’John’);<br />

mary.setName(’Mary’);<br />

john := mary;<br />

john.setName(’Johnny’);<br />

Transcript.print:(mary.name);<br />

Transcript.cr;<br />

end;<br />

In the example above, the variables john and mary initially refer to two different Person<br />

objects, one named ’John’ and another named ’Mary’, respectively. Once mary has been<br />

assigned to john, they both refer to the same object, the Person object with the name<br />

’Mary’. If we change john’s name to ’Johnny’, mary’s name will be changed at the same<br />

time. As a result, ’Johnny’ is printed, when mary’s name is reque<strong>st</strong>ed.<br />

3.3.1 Declaration<br />

A variable declaration defines the name and the type of each variable. Variables with the<br />

same type can be declared in the same declaration by separating their names by commas.<br />

variableDeclaration ::=<br />

variableName ( , variableName )* : typeDescription<br />

The name of a variable is an identifier that consi<strong>st</strong>s of a sequence of uppercase or<br />

lowercase letters (A-Z, a-z) and digits (0-9) which mu<strong>st</strong> <strong>st</strong>art with a letter. The name(s) and<br />

the type are separated by a colon character. In the current version (<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> version 3.00),<br />

the colon mu<strong>st</strong> be preceded by a space, a tab or a newline character, otherwise the compiler<br />

issues a syntax error.<br />

temps<br />

i, counter : SmallInteger;<br />

arr : Array(10);<br />

In the temps section above, i and counter are both declared as variables of type<br />

SmallInteger. The variable arr is declared of type Array(10), that is, an array with 10<br />

elements of unspecified type. In these declarations, SmallInteger and Array(10) are so<br />

called typedescriptions.<br />

3.3.2 Typedescription<br />

A typedescription describes the type of the variable. It refers to a class and can have<br />

arguments. For some variables, it is also used to create their initial value (see below).<br />

There are four forms of typedescriptions:<br />

typeDescription ::=<br />

Any<br />

| className ( ( expression ( , expression )* ) )?<br />

| className selector ( ( expression ( , expression )* ) )?<br />

| variableName<br />

The type Any The type Any can be used for variables whose type do not matter. An object of arbitrary<br />

type can be assigned to such a variable. The initial value of variables of type Any and<br />

which are automatically created (see below) is nil.<br />

Chapter 3: Basic language elements


Ordinary<br />

typedescription<br />

Typedescription<br />

with con<strong>st</strong>ructor<br />

Dynamic<br />

typedescription<br />

The ordinary typedescription consi<strong>st</strong>s of the name of a class, optionally with argument<br />

expressions which are used to initialize the in<strong>st</strong>ance. In<strong>st</strong>ances of <<strong>st</strong>rong>Sina</<strong>st</strong>rong> classes are<br />

con<strong>st</strong>ructed using this form, but it can also be used for the declaration of a Smalltalk<br />

in<strong>st</strong>ance. In the following example, the in<strong>st</strong>ance variable bb is declared as an in<strong>st</strong>ance of<br />

the <<strong>st</strong>rong>Sina</<strong>st</strong>rong> class TypedBuffer. It expects two arguments, the size of the buffer and the type of<br />

its elements.<br />

in<strong>st</strong>vars<br />

bb : TypedBuffer(2 * n, SmallInteger);<br />

TypedBuffer(2 * n, SmallInteger) is the typedescription of the variable bb. It has two<br />

argument expressions, 2*n and SmallInteger. Note that the argument SmallInteger is an<br />

object here, and not a typedescription. Therefore, it should have been declared as an<br />

external of type Class, otherwise the compiler flags it as an ‘Object not declared’-error.<br />

The third form of typedescription consi<strong>st</strong>s of the name of a Smalltalk class followed by a<br />

con<strong>st</strong>ructor and, optionally, argument expressions. The con<strong>st</strong>ructor is a Smalltalk selector<br />

and is sent to the class to con<strong>st</strong>ruct an in<strong>st</strong>ance of that class. Note that this form is only<br />

allowed for Smalltalk classes, and that this class mu<strong>st</strong> have a class method 1 with the<br />

mentioned selector. It is responsibility of the programmer to assure that this class method<br />

does return a new in<strong>st</strong>ance of the class. Table B-2, page 151, describes the relationship<br />

between this form and Smalltalk. We show example declarations using this<br />

typedescription.<br />

temps<br />

today : Date today;<br />

center : Point x:y:(260,435);<br />

circle : Circle center:radius:(center, 50);<br />

pi : Double pi;<br />

The variable today is initialized with today’s date, center is a Point in<strong>st</strong>ance with initial x<br />

and y coordinates, and the variable circle is a Circle in<strong>st</strong>ance with a radius of 50 and the<br />

former center variable as center. Note that we can use previously defined variables in the<br />

typedescription argument expressions. The la<strong>st</strong> declaration shows that the variable pi is<br />

initialized with the Double value of the con<strong>st</strong>ant π.<br />

The final form is the dynamic typedescription. It consi<strong>st</strong>s of the name of a variable, called<br />

the typevariable, which mu<strong>st</strong> have been declared as a variable of the type Class. This form<br />

can be used to declare variables of dynamic type. Such a dynamically typed variable is<br />

initialized with an in<strong>st</strong>ance of the class referred to by the typevariable. Because the<br />

parameters of a class cannot be specified in this form, only classes which have no<br />

parameters can be used safely as value of the typevariable. Classes which require<br />

parameters, such as the earlier mentioned TypedBuffer class, can be used, but their<br />

parameters are initialized with nil. Whether this will lead to (run-time) errors, depends on<br />

the robu<strong>st</strong>ness of that class.<br />

newIn<strong>st</strong>anceOfType(t : Class) returns t;<br />

temps in<strong>st</strong>ance : t;<br />

begin<br />

return in<strong>st</strong>ance<br />

end;<br />

exampleMethod<br />

temps obj1, obj2, obj3 : Any;<br />

begin<br />

obj1 := inner.newIn<strong>st</strong>anceOfType(SmallInteger);<br />

obj2 := inner.newIn<strong>st</strong>anceOfType(Array);<br />

1. We are talking about Smalltalk classes here. A class method of a Smalltalk class will be executed by the<br />

class, whereas an in<strong>st</strong>ance method will be executed by an in<strong>st</strong>ance of that class. Some class methods will<br />

return a new in<strong>st</strong>ance of the class, while other are used for different purposes.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

27


28<br />

obj3 := inner.newIn<strong>st</strong>anceOfType(TypedBuffer);<br />

end;<br />

The parameter t of the method newIn<strong>st</strong>anceOfType above, is the typevariable for the local<br />

variable in<strong>st</strong>ance. This method returns an in<strong>st</strong>ance of type t that is passed as a parameter to<br />

the method. In the exampleMethod, obj1 will be a SmallInteger, obj2 will be an (empty)<br />

Array, and obj3 will be a TypedBuffer in<strong>st</strong>ance with nil as size and elementtype.<br />

3.3.3 Initial value<br />

A variable has an initial value, that is, the variable initially refers to some object.<br />

Parameter variables are initialized with the actual argument objects. Except for externals,<br />

to the other types of variables a new in<strong>st</strong>ance is assigned. The new in<strong>st</strong>ance is con<strong>st</strong>ructed<br />

according to variable’s typedescription. An external variable refers to an exi<strong>st</strong>ing object —<br />

outside its owner— and is therefore not created. When their owner is created, it is verified<br />

whether the externals exi<strong>st</strong>.<br />

Table 3-1 shows for each type of variable whether an in<strong>st</strong>ance for it is created<br />

automatically and when this is done. For Smalltalk classes, an in<strong>st</strong>ance is con<strong>st</strong>ructed<br />

according to appendix B.1 (page 151).<br />

TABLE 3-1 Initial value of variables<br />

Kind of variable<br />

In<strong>st</strong>ance<br />

con<strong>st</strong>ructed<br />

automatically When<br />

temps yes at method invocation time<br />

method<br />

parameters<br />

no passed as actual argument of a message<br />

in<strong>st</strong>vars yes at the in<strong>st</strong>ance creation time of the owning object<br />

internals yes at the in<strong>st</strong>ance creation time of the owning object<br />

externals no their exi<strong>st</strong>ence are verified when the owning<br />

object is created<br />

class parameters no passed as actual arguments of a variable<br />

declaration<br />

3.3.4 Assignment<br />

With the assignment <strong>st</strong>atement, the value of a variable can be changed. It has the following<br />

syntax.<br />

assignmentStatement ::=<br />

variableName := expression ;<br />

All variables can be changed with an assignment, with one exception: it is not allowed to<br />

change the value of a method parameter 2 . By assigning a new object to an external or an<br />

internal, the behavior of the owner could be modified. This is in general considered<br />

dangerous, but it is allowed. The compiler therefore issues a warning when this happens.<br />

3.4 Global externals<br />

A global external is an object which is <strong>st</strong>ored in the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Repository. This is a collection of<br />

global objects which can be used as an external of a class or main method.<br />

2. Due to the implementation in Smalltalk. Smalltalk does not allow method parameters to be changed either.<br />

Chapter 3: Basic language elements


Creating a new<br />

global external<br />

Smalltalk classes and objects are also contained in the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Repository. By declaring the<br />

Smalltalk object as an external with its class as type, the object can be accessed in a <<strong>st</strong>rong>Sina</<strong>st</strong>rong><br />

class or in main.<br />

In the following example, the Smalltalk classes Time and Double are used to<br />

display the current time and the value of the con<strong>st</strong>ant π on the Smalltalk sy<strong>st</strong>em Transcript.<br />

main<br />

externals<br />

Time, Double : Class;<br />

Transcript : TextCollector;<br />

begin<br />

Transcript.print:(Time.now);<br />

Transcript.cr;<br />

Transcript.print:(Double.pi);<br />

Transcript.cr;<br />

Transcript.flush<br />

end<br />

When in main a value is assigned to an external that did not exi<strong>st</strong> before, it causes the<br />

creation of that external which is <strong>st</strong>ored in the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Repository automatically. A value<br />

assigned to an exi<strong>st</strong>ing external in main only changes the value of the global external.<br />

By declaring a local variable —temp— in main of the same type as the non exi<strong>st</strong>ing<br />

external and assigning this object to the external, the external is created and <strong>st</strong>ored in the<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Repository.<br />

The following example shows the creation of the external Hello of class HelloWorld.<br />

main<br />

externals Hello : HelloWorld; // Hello does not exi<strong>st</strong> yet<br />

temps newGlobal : HelloWorld ;<br />

begin<br />

Hello := newGlobal; // Hello will now be <strong>st</strong>ored in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Repository<br />

end<br />

After executing it, you can select the repository option from the source code view<br />

menu to see that the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Repository now includes the object Hello.<br />

3.5 Pseudo variables<br />

There are seven pseudo variables whose values change according to the execution context,<br />

and cannot be changed with an assignment. They are:<br />

• sender;<br />

• server;<br />

• self;<br />

• inner;<br />

• message;<br />

• ^self;<br />

• ^server.<br />

These pseudo variables refer to objects involved in the execution of a single message.<br />

When a message is sent, it is filtered fir<strong>st</strong>. Eventually a method is invoke (see chapter 10<br />

for a more elaborate description of message execution). The aforementioned pseudo<br />

variables can be referred to inside a condition during the filtering of the message, and<br />

inside a method during its execution.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

29


30<br />

sender<br />

server<br />

The fir<strong>st</strong> three pseudo variables, self, server and sender, are fir<strong>st</strong>-class objects, while inner,<br />

message, ^self and ^server are not. The latter four pseudo variables can only be accessed<br />

by sending a message to them, but they cannot be assigned to a variable.<br />

The pseudo variable sender refers to the object which has sent the message. The pseudo<br />

variable server refers to the object to which the message was sent: it is the fir<strong>st</strong> object to<br />

receive the message. The input filters of this object can decide to delegate the message to<br />

another object (an internal or external) in which case the input filters of that object filter<br />

the message. Alternative the input filters may decide to delegate the message to inner. This<br />

results in the invocation of a method.<br />

self During the filtering of a message, the pseudo variable self refers to the object that currently<br />

is filtering it. Once the message has invoked a method, that is, during the method’s<br />

execution, self refers to the object which is executing the method. The pseudo variables<br />

self and server do not refer to the same object when the server has delegated the message<br />

to another object than itself. They do refer to the same object when the server (i.e. the fir<strong>st</strong><br />

receiver) delegated the message to itself.<br />

inner The pseudo variable inner refers to the inner object (see section 2.1.1). Unlike self, inner<br />

refers to the object without the filters. When a message is sent to self, the message is<br />

filtered by the output filters and then by self’s input filters. A message sent to inner on the<br />

other hand, does not pass filters, but invokes a method of the object directly.<br />

message The pseudo variable message can also be referred to inside a condition and method. In the<br />

former case it refers to the message being filtered, while in the latter case, it refers to the<br />

message which lead to the invocation of the method. The pseudo variable message is an<br />

in<strong>st</strong>ance of class ActiveMessage. The attributes of a message (selector, arguments, sender,<br />

server and current receiver) can be retrieved by sending the appropriate message to<br />

message (see section 10.2).<br />

^self<br />

^server<br />

The final two pseudo variables, ^self and ^server, are object managers related to self and<br />

server, respectively. They are in<strong>st</strong>ances of class ObjectManager and can be referred to<br />

inside a condition or a method. An object manager controls the access to an object: it keeps<br />

track of how many messages have been received or sent and which methods are executing<br />

(see section 6.3).<br />

Chapter 3: Basic language elements


4 Expressions<br />

An expression represents some value: when an expression is evaluated it returns an object.<br />

This object could be used to send a message to, but it could also be assigned to a variable,<br />

or passed as parameter to a method.<br />

EXAMPLE 4-1 Tarzan.setName(’Tarzan’, ’King of the Jungle’);<br />

Jane.age < Tarzan.age<br />

Example 4-1 shows the use of two expressions. The fir<strong>st</strong> expression is a so called message<br />

expression: the message setName with two arguments is sent to the receiver object Tarzan.<br />

Note that the two arguments are expressions on their own. The second expression is a so<br />

called operator expression: the two message expressions Jane.age and Tarzan.age are<br />

combined with the less-than operator (


32<br />

• a literal con<strong>st</strong>ant: a number literal (e.g. 3.14), a character literal (e.g. $p) or a <strong>st</strong>ring<br />

literal (e.g. ’King of the Jungle’);<br />

• one of the special literals nil, true or false;<br />

• one of the pseudo variables self, server, or sender;<br />

• a variable: the name of a local variable, a method parameter, an in<strong>st</strong>ance variable, an<br />

internal, an external, or a class parameter.<br />

In example 4-1, the two <strong>st</strong>ring literal arguments of the message setName are operand<br />

objects. Likewise, the variables Jane and Tarzan serve as receivers in both expressions.<br />

Note that the pseudo variables inner and message, and the object managers ^self and<br />

^server do not represent fir<strong>st</strong> class objects. This means that they cannot be passed as an<br />

argument of a message or assigned to a variable on their own. They can be used as the<br />

receiver in a message expression, however.<br />

The syntax of the entities we have defined in this section is as follows.<br />

expression ::=<br />

operandObject | messageExpression | operatorExpression<br />

operandObject ::=<br />

variable | numberLiteral | characterLiteral | <strong>st</strong>ringLiteral | nil | true<br />

| false | self | server | sender<br />

4.2 Message expression<br />

A message expression denotes a message that is sent to an object. It has three main<br />

components: a receiver, a method selector and zero or more arguments. In the message<br />

expression Tarzan.setName(’Tarzan’, ’King of the Jungle’), the receiver is Tarzan, the<br />

method selector is setName, and the two arguments are the <strong>st</strong>ring literals ’Tarzan’ and ’King<br />

of the Jungle’.<br />

Receiver The receiver of a message expression can be one of the following:<br />

• an operand object (section 4.1);<br />

• one of the pseudo variables inner or message;<br />

• an object manager: ^self or ^server;<br />

• an expression enclosed by parentheses;<br />

• a message expression.<br />

Method selector The method selector is separated from the receiver object by a message send dot. A<br />

method selector refers to the name of a method and consi<strong>st</strong>s of a sequence alphanumeric<br />

characters. Apart from the name of a method, a Smalltalk keyword selector is also allowed<br />

as method selector.<br />

The Smalltalk keyword selector can be used to send a message to an in<strong>st</strong>ance of a<br />

Smalltalk class. A Smalltalk keyword selector contains a non-empty sequence of<br />

alphanumeric words each ending with a colon. The method selector at:put: in the<br />

expression anArray.at:put:(i, 0) is an example of such a keyword selector. The <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong><br />

compiler will check, wherever it can, if the Smalltalk class has defined a method with such<br />

a selector.<br />

Note that the method of a Smalltalk class has one of the following three types of selectors:<br />

• a unary selector, which consi<strong>st</strong>s of alphanumeric characters only, for in<strong>st</strong>ance sin. A<br />

unary selector expects no arguments;<br />

Chapter 4: Expressions


• a binary selector, which consi<strong>st</strong>s of non-alphanumeric characters. A binary selector has<br />

only one argument. The selector == is an example;<br />

• a keyword selector, such as the at:put: selector. A keyword selector expects as<br />

many arguments as there are colons in the selector.<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>, a Smalltalk method with a unary or keyword selector can be called by ju<strong>st</strong> using<br />

that selector as the method selector of a message. For a method with a binary selector you<br />

mu<strong>st</strong> use the method selector as defined in table table B-3 (appendix B, page 151).<br />

EXAMPLE 4-2 3.14.sin // Smalltalk unary selector 3.14 sin<br />

’Tar’.cat(’zan’) // Smalltalk binary selector ’Tar’ , ’zan’<br />

anArray.at:put:(i, 0) // Smalltalk keyword selector anArray at: i put: 0<br />

The previous example shows how in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> the Smalltalk selectors can be used. Note that<br />

in Smalltalk the arguments of a keyword selector are mingled with it. In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>, however,<br />

the message arguments are joined together after the selector.<br />

Message arguments The arguments of a message expression are enclosed by parentheses and separated by<br />

commas. If a message expression has no arguments, the enclosing parentheses are omitted.<br />

An argument is an expression, again.<br />

Highe<strong>st</strong> priority<br />

evaluated fir<strong>st</strong>. Equal<br />

priorities evaluated from<br />

left to right<br />

We conclude this section by giving the syntax of the message expression.<br />

messageExpression ::=<br />

receiver . selector ( ( expression ( ; expression )* ) )?<br />

receiver ::=<br />

variable | numberLiteral | characterLiteral | <strong>st</strong>ringLiteral | nil | true<br />

| false | self | server | sender | inner | message | ^self<br />

| ^server | ( expression ) | messageExpression<br />

4.3 Operator expression<br />

An operator expression, such as 3+4*5, improves the readability of the source code and<br />

allows the programmer to write a short-hand notation in<strong>st</strong>ead of the more tedious, but<br />

equivalent message expression 3.plus(4.times(5)). <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>’s compiler will convert each<br />

operator expression simply to an equivalent message expression. It is important to note<br />

that only the selector of the equivalent message expression will be sent to the receiver<br />

object: in the example above, 3 receives the a message with selector plus and not +, and 4<br />

will receive times and not *.<br />

An operator expression is made up of an operator and one or more operands each of<br />

which is an expression again: an operand object, an operator expression, or a message<br />

expression.<br />

Table 4-1 li<strong>st</strong>s the available operators, their priorities and their equivalent message<br />

expressions. For clarity, the table includes the parentheses () and the message send dot (.),<br />

although they are <strong>st</strong>rictly spoken no operators. A message send will always evaluated<br />

before any operator is applied. Parentheses can be used to enforce an evaluation order.<br />

An operator with the highe<strong>st</strong> priority will be evaluated before an operator with a lower<br />

priority. Operators with equal priority will be evaluated from left to right if and only if the<br />

operator is left-associative. A left-associative operator is indicated by a bullet • in the<br />

column "asso-ciates left" of table 4-1. A cross × in the same column indicates that the<br />

operator cannot be combined with operators having the same priority. For in<strong>st</strong>ance,<br />

Jane.age = Tarzan.age = 50 makes no sense and will be flagged by the compiler as a<br />

syntax error. By using parentheses, we could write (Jane.age = Tarzan.age) = false,<br />

though.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

33


34<br />

TABLE 4-1 Operators with their priority and equivalent message expression<br />

associates<br />

sample<br />

description operator priority left expression<br />

force order ( ) >7 × (a / b).floor<br />

message send . >7 • a.atput(b,c)<br />

The <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> compiler transforms an operator expression into a message expression as li<strong>st</strong>ed<br />

in the column labeled "equivalent message expression" of table 4-1. The priorities of the<br />

operators will be taken into account.<br />

EXAMPLE 4-3 Jane.age < Tarzan.age Jane.age.less(Tarzan.age)<br />

(b*b - 4*a*c).sqrt ( (b.times(b)).minus( 4.times(a).times(c) ) ).sqrt<br />

-x+ y.cos + x*y/4 (x.negated).add(y.cos).add(x.times(y).divide(4))<br />

a>=0 and a= × a >= b a.atlea<strong>st</strong>(b)<br />

value equality = 3 × a = b a.equal(b)<br />

value inequality != × a != b a.unequal(b)<br />

identity equality == × a == b a.same(b)<br />

identity inequality =!= × a =!= b a.different(b)<br />

logical disjunction and 2 • a and b a.and(b)<br />

logical conjunction or 1 • a or b a.or(b)


Use the method selector quo: for integer division with truncation toward zero. Thus, -<br />

9.quo:(4) = -2 and -0.9.quo:(0.4) = -2. The method rem: gives the corresponding<br />

remainder: 9.rem:(4) = 1, -9.rem:(4) = -1. 0.9.rem:(0.4) = 0.1.<br />

• The operators = and !=, and the corresponding method selectors equal and unequal, are<br />

used to te<strong>st</strong> whether the values of two objects are equal. The operators == and =!=, and<br />

the respective method selectors same and different, te<strong>st</strong> the whether the two operands<br />

(the receiver and the argument object) are the same object. Thus, 4 = 4.0 yields true,<br />

whereas 4 == 4.0 yields false, since the SmallInteger object 4 and the Float object 4.0<br />

represent the same values, but are two different objects.<br />

• Case differences are ignored when two <strong>st</strong>rings are compared by the operators =, !=, =, and the respective method selectors equal, unequal, less, upto, greater or<br />

atlea<strong>st</strong>. This is due to implementation of the comparison methods of the Smalltalk class<br />

String.<br />

Thus, ’A’ < ’a’ and ’A’ > ’a’ both evaluate to false, even though the ASCII value of the<br />

character $A is less than the ASCII value of $a. The expression ’A’ = ’a’ would evaluate<br />

to true, and therefore ’A’ != ’a’ yields false. The comparison methods do, however,<br />

consider the length of the <strong>st</strong>rings: ’a’ < ’ab’ and ’a’ > ’ab’ yield true and false,<br />

respectively.<br />

To compare <strong>st</strong>rings considering case differences, you should use the method<br />

trueCompare: which returns -1, 0 or 1 if the receiver is less than, equal to, or greater<br />

than the argument. Thus, ’A’.trueCompare:(’a’) yields -1.<br />

We conclude this chapter by giving the syntax of an operator expression.<br />

operatorExpression ::=<br />

monadicOperator operand<br />

| operand dyadicOperator operand<br />

operand ::=<br />

operandObject | operatorExpression | messageExpression<br />

monadicOperator ::=<br />

not | -<br />

dyadicOperator ::=<br />

or | and | = | != | == | =!= | < | | > | - | + | * | /<br />

| div | mod<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

35


36<br />

Chapter 4: Expressions


5 Control <strong>st</strong>ructures<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> defines three control <strong>st</strong>ructures, one conditional selection <strong>st</strong>atement and two<br />

iterative con<strong>st</strong>ructs:<br />

• the conditional <strong>st</strong>atement;<br />

• the for <strong>st</strong>atement;<br />

• the while <strong>st</strong>atement.<br />

5.1 The conditional <strong>st</strong>atement<br />

The conditional <strong>st</strong>atement can be used to choose between two alternatives. Its syntax is as<br />

follows.<br />

conditionalStatement ::=<br />

if expression<br />

then <strong>st</strong>atements<br />

( else <strong>st</strong>atements )?<br />

end<br />

Evaluation of the expression mu<strong>st</strong> yield an in<strong>st</strong>ance of class Boolean, that is, either true or<br />

false. If it yields true, the <strong>st</strong>atements in the then-part will be executed. The else-part is<br />

optional, but when present, the <strong>st</strong>atements in it will be executed when the expression<br />

yielded false. The following example determines the maximum and minimum of two<br />

variables a and b.<br />

EXAMPLE 5-1 if a < b<br />

then min := a; max := b<br />

else min := b; max := a<br />

end<br />

5.2 The for <strong>st</strong>atement<br />

The for <strong>st</strong>atement is used for iteration over numbers. It has the following syntax.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

37


38<br />

forStatement ::=<br />

for loopvar := <strong>st</strong>artExpression to endExpression ( by <strong>st</strong>epExpression )?<br />

begin<br />

<strong>st</strong>atements<br />

end<br />

The variable loopvar mu<strong>st</strong> have been declared before it can be used, for in<strong>st</strong>ance as a local<br />

variable or as an in<strong>st</strong>ance variable. Inside the loop, it is not allowed to change the value of<br />

loopvar, but you can assign a value to it outside the loop. The value of loopvar after the<br />

loop has finished is not defined. Before the iteration of the loop, the <strong>st</strong>artExpression,<br />

endExpression and <strong>st</strong>epExpression will be evaluated respectively to determine the <strong>st</strong>art<br />

value, end value and <strong>st</strong>ep value of the loop. The by <strong>st</strong>epExpression can be omitted, in<br />

which case a <strong>st</strong>ep value of 1 is used. The loopvariable loopvar will be initialized with the<br />

<strong>st</strong>art value. The <strong>st</strong>atements in the body will be executed as long as the value of loopvar<br />

does not exceed the end value. After each iteration, the <strong>st</strong>ep value will be added to the<br />

value of loopvar. For positive <strong>st</strong>ep values this means that the loop iterates while the value<br />

of the loopvar is less than or equal to the end value, and for negative <strong>st</strong>ep values while the<br />

value of the loopvar is greater than or equal to the end value.<br />

In the following example, f’s values are calculated from -2 to 2 in increments of 1/8 and<br />

plotted on the screen.<br />

EXAMPLE 5-2 for x := -2.0 to 2.0 by 0.125<br />

begin<br />

screen.plot(x, f.value(x) )<br />

end<br />

5.3 The while <strong>st</strong>atement<br />

The while <strong>st</strong>atement is used for iteration while some condition is met. It has the following<br />

form.<br />

whileStatement ::=<br />

while expression<br />

begin<br />

<strong>st</strong>atements<br />

end<br />

Evaluation of the expression mu<strong>st</strong> yield an in<strong>st</strong>ance of class Boolean, that is, either true or<br />

false. The <strong>st</strong>atements in the body will be executed repeatedly until the evaluation of the<br />

expression yields false.<br />

The following example could be part of a window controller which tracks the mouse until<br />

a button is released.<br />

EXAMPLE 5-3 while mouse.buttonPressed<br />

begin<br />

mouse.track<br />

end<br />

Chapter 5: Control <strong>st</strong>ructures


6 Classes and<br />

in<strong>st</strong>ances<br />

In this chapter we will describe de <strong>st</strong>ructure of a class (section 6.1) and how an in<strong>st</strong>ance of<br />

a such a class is created (section 6.2). Section 6.3 describes the object manager which<br />

controls such an in<strong>st</strong>ance.<br />

6.1 Class declaration<br />

A class declaration consi<strong>st</strong>s of two parts, the interface part and the implementation part.<br />

The interface part can be preceded by class switches which can be used to control<br />

properties of a class. The class switches will be described after the interface and<br />

implementation part.<br />

classDeclaration ::=<br />

( classSwitch )* interfacePart implementationPart<br />

It is not allowed to define a class with the same name as an exi<strong>st</strong>ing Smalltalk class,<br />

although an exi<strong>st</strong>ing <<strong>st</strong>rong>Sina</<strong>st</strong>rong> class can be redefined.<br />

6.1.1 The interface part<br />

The interface part of a class defines<br />

• its name after the keyword class;<br />

• its parameters between the class name and the keyword interface. The parameters are<br />

surrounded by parentheses which mu<strong>st</strong> be omitted if the class has no parameters;<br />

• an interface comment in the section with the keyword comment;<br />

• the externals in the section with the keyword externals;<br />

• the internals in the section with the keyword internals;<br />

• the conditions in the section with the keyword conditions;<br />

• interface methods in the section with the keyword methods;<br />

• the set of input filters in the section with the keyword inputfilters;<br />

• the set of output filters in the section with the keyword outputfilters;<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

39


40<br />

The general form of the interface part of a class is shown below. Some sections or parts of<br />

them can be omitted. The minimal interface of a class is comprised of the keyword class,<br />

its name and the keywords interface and end.<br />

interfacePart ::=<br />

class className classParameters? interface<br />

( comment <strong>st</strong>ring ; )?<br />

( externals ( variableDeclaration ; )* )?<br />

( internals ( variableDeclaration ; )* )?<br />

( conditions ( conditionDeclaration ; )* )?<br />

( methods ( interfaceMethodDeclaration ; )* )?<br />

( inputfilters ( filterDeclaration ; )* )?<br />

( outputfilters ( filterDeclaration ; )* )?<br />

end ;<br />

classParameters ::=<br />

( variableDeclaration ( ; variableDeclaration )* )<br />

6.1.2 The implementation part<br />

The implementation part of a class defines<br />

• its name after the keyword class. The name mu<strong>st</strong> be the same as in the interface part;<br />

• an implementation comment in the section with the keyword comment;<br />

• the in<strong>st</strong>ance variables in the section with the keyword in<strong>st</strong>vars;<br />

• the condition implementations in the section with the keyword conditions;<br />

• the implementation of the initial method in the section with the keyword initial;<br />

• the method implementations in the section with the keyword methods;<br />

The syntax of the implementation part is shown below. Some sections or parts of them can<br />

be omitted. The minimal implementation of a class is comprised of the keyword class, its<br />

name and the keywords implementation and end.<br />

implementationPart ::=<br />

class className implementation<br />

( comment <strong>st</strong>ring ; )?<br />

( in<strong>st</strong>vars ( variableDeclaration ; )* )?<br />

( conditions ( conditionImplementation ; )* )?<br />

( initial ( methodBody ; )* )?<br />

( methods ( methodImplementation ; )* )?<br />

end ;<br />

6.1.3 Class switches<br />

A class switch can be used to control properties of a class, such as default behavior and<br />

mutual exclusion. A switch will apply to a single class. Currently supported class switches<br />

are:<br />

#Category ’A category’;<br />

#DefaultObject;<br />

#NoDefaultObject;<br />

#DefSyncFilter;<br />

#NoDefSyncFilter;<br />

#DefBehaviorFilter;<br />

#NoDefBehaviorFilter;<br />

Chapter 6: Classes and in<strong>st</strong>ances


Default behavior and<br />

synchronization<br />

The keywords of the switches are not case-sensitive: #defaultobject; #DEFAULTOBJECT;<br />

and #DefaultObject all denote the same switch. The switches will be described below.<br />

When a class has no switches defined, the class will provide default behavior and mutual<br />

exclusion. The compiler will realize this by inserting<br />

• an internal default of type <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object;<br />

• an input wait filter defSync which provides mutual exclusion for every in<strong>st</strong>ance of the<br />

class;<br />

• the conditions free and recursive which are used in the defSync filter;<br />

• an input dispatch filter defBehavior which provides default behavior for every in<strong>st</strong>ance<br />

of the class;<br />

#Category ’A category’; This switch controls the category in the Smalltalk sy<strong>st</strong>em dictionary in which the compiled<br />

class will be <strong>st</strong>ored. When this switch is not specified, the class will be <strong>st</strong>ored in the<br />

category defined in the user intrface window (refer to section 14.2, page 129).<br />

#DefaultObject;<br />

#NoDefaultObject;<br />

These switches define whether or not an internal called default of type <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object will be<br />

inserted by the compiler automatically. Class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object implements default behavior for<br />

a class, such as printing, copying, etc. (see appendix A.1, page 147). The definition of the<br />

internal is:<br />

internals<br />

default : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object;<br />

The object default will be inserted<br />

• if the switch #DefaultObject; has been specified, or<br />

• if the switch #NoDefaultObject; has not been specified.<br />

The object default will be omitted<br />

• if the switch #NoDefaultObject; has been specified, or<br />

• if the class already has an external, internal or in<strong>st</strong>ance variable of an arbitrary type<br />

called default.<br />

When the internal default is inserted, it will be inserted as the fir<strong>st</strong> internal of the class.<br />

Table 6-1 illu<strong>st</strong>rates where the internal default will be inserted.<br />

TABLE 6-1 Location of the internal default.<br />

#DefSyncFilter;<br />

#NoDefSyncFilter;<br />

// no switch specified #DefaultObject; #NoDefaultObject;<br />

class X interface class X interface class X interface<br />

externals ... externals ... externals ...<br />

internals internals internals<br />

default : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object; default : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object;<br />

a : A; a : A; a : A;<br />

b : B; b : B; b : B;<br />

... ... ...<br />

conditions ... conditions ... conditions ...<br />

methods ... methods ... methods ...<br />

inputfilters ... inputfilters ... inputfilters ...<br />

outputfilters ... outputfilters ... outputfilters ...<br />

end; end; end;<br />

These switches determine whether or not the input wait filter defSync will be inserted.<br />

This filter provides mutual exclusion for each in<strong>st</strong>ance of the class. The input wait filter<br />

defSync has the following definition:<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

41


42<br />

#DefBehaviorFilter;<br />

#NoDefBehaviorFilter;<br />

defSync : Wait = { {free, recursive}=>inner.*, true~>inner.*};<br />

The input wait filter defSync will be inserted<br />

• if the switch #DefSyncFilter; has been specified, or<br />

• if the switch #NoDefSyncFilter; has not been specified.<br />

The input wait filter defSync will be omitted<br />

• if the switch #NoDefaultObject; was specified, or<br />

• if the switch #NoDefSyncFilter; was specified, or<br />

• if the class already has an input filter called defSync.<br />

When the input waitf ilter defSync is inserted, it will be inserted before the fir<strong>st</strong> input filter<br />

that is not a wait filter. When no input filters are defined, or all the input filters are wait<br />

filters, the defSync filter will be placed after the la<strong>st</strong> after input filter.<br />

When this filter is inserted, the conditions free and recursive will also be inserted unless<br />

the are already defined. Their implementations are defined as:<br />

conditions<br />

free begin return ^self.active = 0 end;<br />

recursive begin return message.isRecursive end;<br />

The defSync filter provides mutual exclusion. Messages with a selector defined by the<br />

class self, i.e. which are in the inner signature, will be blocked by the filter when there is<br />

already a local method active. Other message, those in the signature of internals or<br />

externals will never be blocked by this filter. The location of the defSync filter are<br />

illu<strong>st</strong>rated in table 6-2.<br />

TABLE 6-2 Location of the input wait filter defSync and the conditions free and recursive.<br />

no switch specified #DefSyncFilter; #NoDefSyncFilter;<br />

class X interface class X interface class X interface<br />

externals ... externals ... externals ...<br />

internals ... internals ... internals ...<br />

conditions conditions conditions<br />

... ... ...<br />

free; free;<br />

recursive; recursive;<br />

methods ... methods ... methods ...<br />

inputfilters inputfilters inputfilters<br />

f1 : Wait = {...}; f1 : Wait = {...}; f1 : Wait = {...};<br />

f2 : Wait = {...}; f2 : Wait = {...}; f2 : Wait = {...};<br />

defSync : Wait = { ...} ; defSync : Wait = { ...} ;<br />

f3 : NonWait = {...}; f3 : NonWait = {...}; f3 : NonWait = {...};<br />

f4 : NonWait = {...}; f4 : NonWait = {...}; f4 : NonWait = {...};<br />

f5 : Wait = {...}; f5 : Wait = {...}; f5 : Wait = {...};<br />

... ... ...<br />

outputfilters ... outputfilters ... outputfilters ...<br />

end; end; end;<br />

These switches define whether or not the input dispatch filter defBehavior will be inserted.<br />

This filter provides the behavior of the default object. The input dispatch filter defBehavior<br />

has the following definition:<br />

defBehavior : Dispatch = { default.* };<br />

Chapter 6: Classes and in<strong>st</strong>ances


The input dispatch filter defBehavior will be inserted<br />

• if the switch #DefBehaviorFilter; has been specified, or<br />

• if the switch #NoDefBehaviorFilter; has not been specified.<br />

The input dispatch filter defBehavior will be omitted<br />

• if the switch #NoDefaultObject; was specified, or<br />

• if the switch #NoDefBehaviorFilter; was specified, or<br />

• if the class already has an input filter called defBehavior.<br />

When the input dispatch filter defBehavior is inserted, it will be inserted before the fir<strong>st</strong><br />

input filter which is not a wait filter. When no input filters are defined, or all the input<br />

filters are wait filters, the defBehavior filter will be placed after the la<strong>st</strong> after input filter.<br />

The location of the filter is shown in table 6-3.<br />

TABLE 6-3 Location of the input dispatch filter defBehavior.<br />

// no switch specified #DefBehaviorFilter; #NoDefBehaviorFilter;<br />

class X interface class X interface class X interface<br />

externals ... externals ... externals ...<br />

internals ... internals ... internals ...<br />

conditions ... conditions ... conditions ...<br />

methods ... methods ... methods ...<br />

inputfilters inputfilters inputfilters<br />

f1 : Wait = {...}; f1 : Wait = {...}; f1 : Wait = {...};<br />

f2 : Wait = {...}; f2 : Wait = {...}; f2 : Wait = {...};<br />

defBehavior : Dispatch = {...} ; defBehavior : Dispatch = {...} ;<br />

f3 : NonWait = {...}; f3 : NonWait = {...}; f3 : NonWait = {...};<br />

f4 : NonWait = {...}; f4 : NonWait = {...}; f4 : NonWait = {...};<br />

... ... ...<br />

outputfilters ... outputfilters ... outputfilters ...<br />

end; end; end;<br />

6.2 An in<strong>st</strong>ance of a class<br />

As described in section 3.3.3, internals, in<strong>st</strong>ance variables and local variables are variables<br />

which will be initialized with a newly created in<strong>st</strong>ance of the class specified in the variable<br />

declaration.<br />

When an in<strong>st</strong>ance of a class is created, or con<strong>st</strong>ructed as it will be called here, its internals<br />

and in<strong>st</strong>ance variables will be con<strong>st</strong>ructed. This means that every internal and in<strong>st</strong>ance<br />

variable will be initialized with an in<strong>st</strong>ance of the class specified in the variable<br />

declaration.<br />

The same applies to the local variables (temps) of a method or main. When the method or<br />

main is invoked, its local variables will be con<strong>st</strong>ructed: each variable will be initialized<br />

with an in<strong>st</strong>ance of the class specified in the variable declaration.<br />

An external, a class or method parameter will not be con<strong>st</strong>ructed, since, in case of an<br />

external, the object already exi<strong>st</strong>s, and in case of a parameter, the object will be passed by<br />

the caller.<br />

When an in<strong>st</strong>ance x of a <<strong>st</strong>rong>Sina</<strong>st</strong>rong> class, say X, is con<strong>st</strong>ructed, the following actions will be<br />

carried out:<br />

• The class parameters of X, if any, will be initialized with the values of the arguments of<br />

x’s declaration at the time of its con<strong>st</strong>ruction;<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

43


44<br />

• The exi<strong>st</strong>ence of the class’ externals will be verified. If there are externals that do not<br />

exi<strong>st</strong>, these will be reported on the object’s window and the creation of the in<strong>st</strong>ance is<br />

aborted with the error ‘Can’t create in<strong>st</strong>ance Y::x’, where x is the in<strong>st</strong>ance of class X<br />

declared as some internal, in<strong>st</strong>ance variable or local variable in class Y;<br />

• The internals will be con<strong>st</strong>ructed. This can, recursively, lead to the con<strong>st</strong>ruction of<br />

in<strong>st</strong>ances of other classes. It is therefore not allowed to declare an internal of the same<br />

class from which it is part of;<br />

• The in<strong>st</strong>ance variables will be con<strong>st</strong>ructed. Again, this can lead to the con<strong>st</strong>ruction of<br />

in<strong>st</strong>ances of other classes. It is neither allowed to declare an in<strong>st</strong>ance variable of the<br />

same class from which it is part of;<br />

• And finally, when class X has defined one, its initial method will be executed.<br />

6.3 The object manager<br />

Every in<strong>st</strong>ance has associated with it a so-called object manager. As the name implies, an<br />

object manager controls an object. It keeps track of the number of methods that have been<br />

invoked and finished, and the number of messages that have been blocked by a wait filter.<br />

An object manager can be referred to by the pseudo variable ^self and ^server. The former<br />

refers to the to the object manager of self while the latter refers to the object manager of<br />

server. An object manager is an in<strong>st</strong>ance of the class ObjectManager which provides the<br />

following methods (see also appendix A.4, page 150):<br />

TABLE 6-4 Methods of an object manager<br />

active returns SmallInteger; Answers the number of active (unfinished)<br />

method invocations in the object. Note that after<br />

an early return, a method <strong>st</strong>ill is active<br />

(executing). The method will finish only when<br />

its la<strong>st</strong> <strong>st</strong>atement has been executed.<br />

activeForMethod(selector : String)<br />

returns SmallInteger;<br />

Chapter 6: Classes and in<strong>st</strong>ances<br />

Answers the number of active (unfinished)<br />

invocations of the method given by the<br />

argument.<br />

blockedReq returns SmallInteger; Answers the number of messages that have been<br />

blocked by an input wait filter.<br />

blockedInv returns SmallInteger; Answers the number of messages that have been<br />

blocked by an output wait filter.


Return and early return<br />

Creating concurrency<br />

The declaration of<br />

an interface method<br />

7 Methods<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>, there are three kinds of methods:<br />

• interface method;<br />

• private method;<br />

• initial method.<br />

The interface method is declared at the interface part of the class and can be called by any<br />

client object. A private method can only be invoked by its owner. Finally, the initial<br />

method is executed automatically at in<strong>st</strong>ance creation time, right after the internals and<br />

in<strong>st</strong>ance variables have been created. Sections 7.1 to 7.3 discuss the three method types in<br />

more detail.<br />

main Apart from these methods, which are bound to a class, <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> also defines the main<br />

method which can be used to <strong>st</strong>art an application. The main method is the subject of<br />

section 7.4.<br />

A method returns a value —an object— when it executes a return <strong>st</strong>atement or the<br />

equivalent object manager message ^self.reply() (see section 7.5). For normal methods, the<br />

return is the la<strong>st</strong> <strong>st</strong>atement that is executed by the method. In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>, however, it is also<br />

possible that the method continues with the execution of <strong>st</strong>atements after the it has<br />

returned a value. In this case, the method is a so called early return method. The<br />

<strong>st</strong>atements following the return are executed concurrently with the method that invoked<br />

the early return method. With an early return method it is thus possible to create<br />

concurrency. Section 7.6 describes when a method is a normal or an early return method,<br />

while section 7.7 shows the difference between the invocation of a normal method and an<br />

early return method.<br />

Finally, section 7.8 describes the <strong>st</strong>atements which are allowed in a method body.<br />

7.1 Interface method<br />

An interface method mu<strong>st</strong> have been declared at the interface part of a class. They are<br />

declared in the section of the interface part which <strong>st</strong>arts with the keyword methods. An<br />

interface method declaration defines the name of the method, the names and types of the<br />

parameters and the type of the object returned from the method, its so-called returntype. If<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

45


46<br />

the returntype is specified as nil, it means that the method always returns the nil object, i.e.<br />

that it does not return a relevant object.<br />

The syntax of an interface method declaration is shown below.<br />

methodDeclarations ::=<br />

( methods ( interfaceMethodDeclaration ; )* )?<br />

interfaceMethodDeclaration ::=<br />

methodName methodParameters? returns returnType<br />

methodName ::=<br />

identifier<br />

methodParameters ::=<br />

( variableDeclaration ( ; variableDeclaration )* )<br />

returnType ::=<br />

nil | typeDescription<br />

The example below shows the interface of class Person which contains the declaration of<br />

three interface methods, setName, birthDay and age.<br />

EXAMPLE 7-1 A class Person interface<br />

comment ’’;<br />

externals<br />

internals<br />

conditions<br />

methods<br />

setName(fir<strong>st</strong>name, surname : String) returns nil;<br />

birthDay returns Date;<br />

age returns SmallInteger<br />

// ... other interface methods<br />

inputfilters<br />

disp : Dispatch = {inner.*};<br />

outputfilters<br />

end; // Person interface<br />

Making an<br />

interface method<br />

available for a client<br />

The fir<strong>st</strong> method, setName, does not return a value and therefore its returntype is nil. The<br />

two other methods, birthDay and age, return an in<strong>st</strong>ance of class Date and SmallInteger,<br />

respectively. The setName method has two parameters of the same type: fir<strong>st</strong>name and<br />

surname both are Strings. The two other two methods, on the other hand, do not have any<br />

parameters.<br />

For an interface method to be able to be invoked by a client object, it is necessary that a<br />

Dispatch filter is declared in the group of input filters which contains a filter element (see<br />

page 64) that refers to the method. The target of such a filter element mu<strong>st</strong> be inner and its<br />

selector mu<strong>st</strong> match with the name of the method: this is the case if the selector of the filter<br />

element either is a wildcard or is same as the name of the method.<br />

In example 7-1 A, the input Dispatch filter disp includes such a filter element. The filters<br />

below exhibit some other combinations of filter elements for the interface methods of<br />

example 7-1. The f1 filter, for example, uses sub<strong>st</strong>itution on a message with selector<br />

dateOfBirth in order to invoke the method birthDay. Thus, if an object sends a message<br />

dateOfBirth to a Person, the birthDay method will be invoked and the date of birth of the<br />

Person will be returned.<br />

f1 : Dispatch = { [*.dateOfBirth]inner.birthDay, nameUnset => inner.setName };<br />

f2 : Dispatch = {..., c2 => inner.*, ...};<br />

Chapter 7: Methods


The implementation<br />

of an interface method<br />

How to call<br />

an interface method<br />

The section of the implementation part of a class which <strong>st</strong>arts with the keyword methods,<br />

embodies the implementations of interface methods. The ordering of the methods is not<br />

important: the methods can be in a different order as they are declared at the interface part<br />

and private methods can be mixed in between as well. The syntax of the implementation of<br />

an interface method is as follows:<br />

interfaceMethodImplementation ::=<br />

methodName methodParameters?<br />

( comment <strong>st</strong>ring ; )?<br />

( temps ( variableDeclaration ; )* )?<br />

begin <strong>st</strong>atements end<br />

The implementation of an interface method duplicates the names and types of the<br />

parameters from the declaration at the interface, and defines further the comment, the<br />

temporary variables and the body of the method. Note that the returntype is not repeated in<br />

the implementation. The example 7-1 B shows the implementation part of class Person<br />

with implementations of the aforementioned interface methods.<br />

An interface method can be called by sending a message, with a selector that is the same as<br />

the name of the method, to an object that supports the method. The setName method of<br />

class Person, for in<strong>st</strong>ance, could be called in the following ways:<br />

• p.setName(’John’, ’Smith’);<br />

In this case, the sending object sends the message to an object p which should be an<br />

in<strong>st</strong>ance of class Person (or even an in<strong>st</strong>ance that eventually delegates the message to<br />

an in<strong>st</strong>ance of class Person);<br />

• self.setName(’John’, ’Smith’);<br />

Here, the sending object sends a message to itself. By sending it to self, the message<br />

passes through the input filters of the object (after it passed through its output filters, to<br />

be precisely, see section 9.2, page 62);<br />

• inner.setName(’John’, ’Smith’);<br />

In this case, the sending object sends the message to inner, which calls the method<br />

directly, that is, without passing through the output filters or input filters.<br />

The implementation of the method age shows also a message sent to inner. The selector of<br />

this method, ageOn, does not refer to an interface method though, but to a private method.<br />

The private method is described in the coming section.<br />

EXAMPLE 7-1 B class Person implementation<br />

comment ’’;<br />

in<strong>st</strong>vars<br />

birthDay : Date;<br />

fir<strong>st</strong>Name, la<strong>st</strong>Name : String;<br />

// ... other in<strong>st</strong>vars<br />

conditions<br />

initial<br />

methods<br />

setName(fir<strong>st</strong>name, surname : String)<br />

comment ’Define new fir<strong>st</strong>Name and la<strong>st</strong>Name’;<br />

temps // ... no temps<br />

begin<br />

fir<strong>st</strong>Name := fir<strong>st</strong>name;<br />

la<strong>st</strong>Name := surname;<br />

end; // setName<br />

birthDay<br />

comment ’Answer my date of birth.’;<br />

begin<br />

return birthDay<br />

end; // birthDay<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

47


48<br />

Joint declaration<br />

and implementation<br />

age<br />

comment ’Answer my current age’;<br />

temps today : Date today;<br />

begin<br />

return inner.ageOn(today)<br />

end; // age<br />

// ... other methods<br />

end; // Person implementation<br />

7.2 Private method<br />

A private method implements some behavior that only available to the owning object.<br />

Therefore, a private method is not declared in the interface part of a class, but its<br />

declaration and implementation are combined and defined in the implementation part. The<br />

implementation of a private method is similar to the implementation of an interface<br />

method. The only difference, though, is that the returntype of the private method is defined<br />

in the header:<br />

privateMethodImplementation ::=<br />

methodName methodParameters? returns returnType<br />

( comment <strong>st</strong>ring ; )?<br />

( temps ( variableDeclaration ; )* )?<br />

begin <strong>st</strong>atements end<br />

In the following example, the private method ageOn returns a SmallInteger which denotes<br />

the Person’s age on the day that is passed as an argument to the method. Note that in this<br />

specific implementation, the Smalltalk class Date is used and also the Smalltalk selectors<br />

subtractDate: and fromDays:.<br />

EXAMPLE 7-2 class Person implementation<br />

// ... same as in example 7-1 B<br />

methods<br />

// ... other methods<br />

How to call<br />

a private method<br />

ageOn(day : Date) returns SmallInteger<br />

comment ’Answer the age of this person on the argument date ”day” ’;<br />

in<strong>st</strong>vars<br />

dateDiff, date0 : Date;<br />

begin<br />

dateDiff := Date.fromDays:(day.subtractDate:(birthDay));<br />

date0 := Date.fromDays:(0);<br />

return dateDiff.year - date0.year<br />

end; // ageOn<br />

end; // Person implementation<br />

A private method can be invoked by the owning object only, by sending a message to the<br />

pseudo variable inner. In this way, the message does not pass the input filters, nor the<br />

output filters, but the method is invoked directly. In the interface method age (see example<br />

7-1 B) the private method ageOn is called with today’s date as an argument.<br />

7.3 Initial method<br />

The initial method is optional and will be executed, if it has been defined, ju<strong>st</strong> after the<br />

in<strong>st</strong>ance has been created, including its internals and in<strong>st</strong>ance variables. This method<br />

allows, for in<strong>st</strong>ance, to initialize internals and in<strong>st</strong>ance variables with specific values. The<br />

initial method is specified in the class’ implementation part of a class, between the<br />

conditions and methods sections.<br />

Chapter 7: Methods


The returntype of the initial method is not specified, but is, by definition nil: the initial<br />

method does not return a value. Neither does it have parameters. Like the private and<br />

interface methods, the implementation of the initial method defines a comment, temporary<br />

variables, both optionally, and the method body:<br />

initialMethodImplementation ::=<br />

initial<br />

( comment <strong>st</strong>ring ; )?<br />

( temps ( variableDeclaration ; )* )?<br />

begin <strong>st</strong>atements end ;<br />

The initial method for class Person is shown in the following example. The name of every<br />

new Person in<strong>st</strong>ance will be initialized with ‘Nomen Nescio’.<br />

EXAMPLE 7-3 class Person implementation<br />

comment ’’;<br />

in<strong>st</strong>vars<br />

// ... from example 7-1 B<br />

conditions<br />

initial<br />

comment ’Define fir<strong>st</strong>Name and la<strong>st</strong>Name’;<br />

temps<br />

begin<br />

fir<strong>st</strong>Name := ’Nomen’;<br />

la<strong>st</strong>Name := ’Nescio’;<br />

end; // initial<br />

methods<br />

// ... from examples 7-1 and 7-2<br />

end; // Person implementation<br />

7.4 Main method<br />

The main method can be used <strong>st</strong>art an application. In general, the main method is very<br />

small, but you can use it to te<strong>st</strong> newly defined classes. We have used the main method<br />

already several times. The syntax form of the main method is as follows:<br />

main ::=<br />

main<br />

( comment <strong>st</strong>ring ; )?<br />

( externals ( variableDeclaration ; )* )?<br />

( temps ( variableDeclaration ; )* )?<br />

begin <strong>st</strong>atements end<br />

The externals and temps sections are used to declare externals and local variables,<br />

respectively. In main, an external refers to a global external <strong>st</strong>ored in the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Repository.<br />

The main method can also be used to create a new external (see section 3.4, page 28). The<br />

body can contain any number of <strong>st</strong>atements.<br />

The main method returns nil. It is possible to perform an early return in main. The main<br />

method can be executed by selecting the run option from the menu in the<br />

source code view (see [Koopmans95]).<br />

7.5 Returning a value from a method<br />

A value —an object— can be returned from a method in two ways:<br />

• by execution of the return <strong>st</strong>atement, or<br />

• by sending the message reply to the object manager ^self.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

49


50<br />

^self.reply message The ^self.reply(...) message is an ordinary message expression (see section 4.2, page 32).<br />

The argument of the reply message is an expression that specifies the value to be returned<br />

by the method.<br />

Return <strong>st</strong>atement A return <strong>st</strong>atement consi<strong>st</strong>s of the keyword return and is optionally followed by an<br />

expression. This expression denotes the value to be returned by the method. The<br />

expression following return can only be omitted if the return value of the method is<br />

specified as nil.<br />

The return <strong>st</strong>atement is actually equivalent to the ^self.reply(...) message. Table 7-1 shows<br />

the equivalence between the return <strong>st</strong>atement and the objectmanager message reply. The<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> compiler translates a return <strong>st</strong>atement into its corresponding reply message.<br />

The interface methods birthDay, age (example 7-1 B), and the private method ageOn<br />

(example 7-2) all show the application of the return <strong>st</strong>atement to yield a value from the<br />

method. By using the objectmanager message reply, the method age, for in<strong>st</strong>ance, could<br />

also be written as follows.<br />

EXAMPLE 7-4 age<br />

comment ’Answer my current age’;<br />

temps today : Date today;<br />

begin<br />

^self.reply( inner.ageOn(today) )<br />

end;<br />

Implicit return if no<br />

return expression<br />

in method body<br />

TABLE 7-1 Equivalence of return <strong>st</strong>atement and object manager message reply<br />

return ^self.reply(nil)<br />

return nil ^self.reply(nil)<br />

return expression ^self.reply(expression)<br />

If a method body does not include a return expression (i.e. a return <strong>st</strong>atement or a<br />

^self.reply message), the return <strong>st</strong>atement return is implicitly the la<strong>st</strong> <strong>st</strong>atement in the<br />

method body. Note that this is only possible for methods whose return value is specified as<br />

nil: the compiler will flag an error if the return value of the method is not nil and its body<br />

does not contain a return expression.<br />

The interface method setName (example 7-1 B) and the initial method (example 7-3) of<br />

class Person are illu<strong>st</strong>rations of methods with an implicit return <strong>st</strong>atement.<br />

Early return Normally, if the method has returned a value, the method finishes its execution. However,<br />

if other <strong>st</strong>atements follow the return in the body of the method, the method will continue to<br />

execute these <strong>st</strong>atements. This kind of method is called an early return method and is<br />

subject of the next section.<br />

7.6 Normal versus early return<br />

In this section we define more precisely if a method is a normal method or an early return<br />

method (definition 7-2). It is based on the notion called control flow. Further, we define<br />

requirements which mu<strong>st</strong> be obeyed by every control flow (definitions 7-3 to 7-5). This<br />

section ends by giving examples of early and normal methods.<br />

DEFINITION 7-1 Control flow in a method<br />

A control flow in a method (or flow for short) is one possible execution of <strong>st</strong>atements of the<br />

method body. The flow <strong>st</strong>arts with the fir<strong>st</strong> <strong>st</strong>atement of the method body, then the next,<br />

etcetera.<br />

There are several flows of control possible if a method body contains a conditional or a<br />

loop <strong>st</strong>atement. In a conditional <strong>st</strong>atement, depending on the value of the condition, the<br />

Chapter 7: Methods


flow can either follow the then or else branch. The <strong>st</strong>atements in the body of a while or for<br />

loop can be executed zero or more times.<br />

For the following method body we have indicated the possible flows of control. One flow,<br />

labeled f 1 , <strong>st</strong>arts by evaluating the condition c1 and, if c1 was true, continues in the then<br />

branch by executing the <strong>st</strong>atement s1 and returning object x (denoted in the flow by ^x).<br />

Further, there is an infinite number of other flows, all indicated by f 2 (i). They all <strong>st</strong>art by<br />

evaluating c1 to false (denoted by ~c1) and then continue with the execution of the while<br />

loop. The <strong>st</strong>atement s2 in the body of the while loop will be executed as long as the<br />

condition c2 evaluates to true (denoted by (c2, s2) i ). The flow ends by returning the object<br />

y after c2 becomes false (shown as ~c2, ^y).<br />

begin<br />

if c1<br />

then s1; return x<br />

else<br />

while c2 begin s2 end<br />

end;<br />

return y<br />

end;<br />

f 1 = c1, s1, ^x<br />

f 2 (i)= ~c1, (c2, s2) i , ~c2, ^y with i=0,1,2,…<br />

Now that we have defined the control flow in a method, we define when a method is a<br />

normal or an early return method.<br />

DEFINITION 7-2 Early return method and normal return method<br />

A method is an early return method if there is a flow in which the return <strong>st</strong>atement is<br />

followed by at lea<strong>st</strong> one other <strong>st</strong>atement.<br />

Consequently, a method is a normal method if the la<strong>st</strong> <strong>st</strong>atement in every flow is a return<br />

<strong>st</strong>atement.<br />

Examples of normal and early return methods are given at the end of this section. In the<br />

following section the difference between the invocation of a normal and an early return<br />

method is explained. But fir<strong>st</strong> we define two rules that mu<strong>st</strong> be valid for every control flow<br />

in a method.<br />

DEFINITION 7-3 Control flow requirements<br />

The following two requirements mu<strong>st</strong> hold for every control flow of a method:<br />

1. In every flow there mu<strong>st</strong> be a return.<br />

2. Only one return is allowed in a flow.<br />

The fir<strong>st</strong> requirement is needed because the method mu<strong>st</strong> always return a value. If this not<br />

the case, the compiler generates the error ‘No value returned in one flow’.<br />

The second requirement is needed because a method can return a value only once. The<br />

compiler produces the error ‘Return after early return is not allowed’ if this requirement is<br />

disregarded.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

51


52<br />

The fir<strong>st</strong> three of the following method bodies do not follow the fir<strong>st</strong> requirement, while<br />

the la<strong>st</strong> breaches the second. The offending elements are highlighted.<br />

begin<br />

begin<br />

s1;<br />

if c<br />

s2;<br />

then<br />

s3;<br />

s1;<br />

end;<br />

return x;<br />

end;<br />

s2;<br />

end;<br />

f= s1, s2, s3 f1 = c, s1, ^x<br />

f2 = ~c, s2<br />

We introduce two further rules, one for the conditional <strong>st</strong>atement and another for the two<br />

loop <strong>st</strong>atements. They are not really necessary since they are already covered by the two<br />

control flow requirements, but they ‘make life easier’.<br />

DEFINITION 7-4 Control flow requirement for the conditional <strong>st</strong>atement<br />

If in a conditional <strong>st</strong>atement either the then-branch or the else-branch has an early return,<br />

there mu<strong>st</strong> be a return in the other branch too.<br />

The <strong>st</strong>atements following the conditional <strong>st</strong>atement are executed after the execution of<br />

either branch. These <strong>st</strong>atements are not allowed to have another return, because of the<br />

early return in one branch. The flow via the other branch thus would have no return,<br />

thereby breaching the fir<strong>st</strong> control flow requirement. The compiler generates the error<br />

‘Early return in one flow, no return in the other’ in case this rule is not satisfied.<br />

DEFINITION 7-5 Control flow requirement for the while and the for <strong>st</strong>atement<br />

An early return inside the body of a loop <strong>st</strong>atement (a while <strong>st</strong>atement or a for <strong>st</strong>atement) is<br />

not allowed, though a normal return is.<br />

This is rule is needed because the body of the loop can be executed several times, and<br />

therefore the (early) return could be executed more than once too. A breach of this rule<br />

causes the compiler to generate the error ‘Early return not allowed inside loop’.<br />

The following two method bodies display violations of these rules.<br />

// Early return in one flow,<br />

// no return in the other<br />

begin<br />

if c<br />

then s1; return x; s2<br />

else s3;<br />

end;<br />

s4;<br />

end;<br />

f 1 = c, s1, ^x, s2, s4<br />

f 2 = ~c, s3, s4<br />

Chapter 7: Methods<br />

begin<br />

while c1<br />

begin<br />

s1;<br />

if c2 then<br />

return x;<br />

end;<br />

end;<br />

s3;<br />

end;<br />

begin<br />

s1;<br />

return x;<br />

s2;<br />

return y;<br />

s3;<br />

end;<br />

f 1 (i)= (c1, s1, ~c2) i , ~c1, s3<br />

f 2 (i)= (c1, s1, ~c2) i ,c1, s1, c2, ^x<br />

with i=0,1,2,…<br />

// Early return not allowed<br />

// inside loop<br />

begin<br />

while c<br />

begin<br />

s1;<br />

return x;<br />

s2;<br />

end;<br />

end;<br />

f(i)= (c, s1, ^x, s2) i , ~c<br />

For in<strong>st</strong>ance if i=2:<br />

f= s1,^x, s2,^y, s3<br />

f(2)= c, s1, ^x, s2, ~c, s1, ^x, s2, ~c


Finally, this section presents examples of normal and early return methods. Example 7-5 A<br />

shows bodies of normal methods and their associated flows of control. Example 7-5 B<br />

shows the method bodies of some early return methods together with their flows.<br />

EXAMPLE 7-5 A Normal method bodies and their control flows.<br />

begin<br />

s1;<br />

s2;<br />

s3;<br />

return x;<br />

end;<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

begin<br />

if c<br />

then s1;<br />

else s2;<br />

end;<br />

s3; return z;<br />

end;<br />

f 1 = s1, s2, s3, ^x f 1 = c, s1, s3, ^z<br />

f 2 = ~c, s2, s3, ^z<br />

begin<br />

if c1<br />

then s1; return x;<br />

end;<br />

if c2<br />

then s3; return y;<br />

end;<br />

s5; return z;<br />

end;<br />

f 1 = c1, s1, ^x<br />

f 2 = ~c1, c2, s3, ^y<br />

f 3 = ~c1, ~c2, s5, ^z<br />

begin<br />

while c<br />

begin<br />

s1;<br />

return x;<br />

end;<br />

s2; return y;<br />

end;<br />

f 1 = c, s1, ^x<br />

f 2 = ~c, s2, ^y<br />

begin<br />

if c1<br />

then s1; return x;<br />

else s3;<br />

if c2<br />

then s5; return y;<br />

else s7; return z;<br />

end;<br />

end;<br />

end;<br />

f 1 = c1, s1, ^x<br />

f 2 = ~c1, s3, c2, s5, ^y<br />

f 3 = ~c1, s3, ~c2, s7, ^z<br />

begin<br />

while c1<br />

begin<br />

s1;<br />

if c2<br />

then s2; return x;<br />

else s3; return y;<br />

end;<br />

end;<br />

s4; return z;<br />

end;<br />

f 1 = c1, s1, c2, s2,^x<br />

f 2 = c1, s1, ~c2, s3,^y<br />

f 3 = ~c1, s4, ^z<br />

begin<br />

if c<br />

then s1; return x;<br />

else s2; return y;<br />

end;<br />

end;<br />

f 1 = c, s1, ^x<br />

f 2 = ~c, s2, ^y<br />

begin<br />

while c<br />

begin s1; s2;<br />

end;<br />

s5; return z;<br />

end;<br />

f(i)= (c, s1, s2) i , ~c, s5, ^z<br />

with i=0,1,2,...<br />

begin<br />

while c1<br />

begin<br />

s1;<br />

if c2<br />

then s2; return y;<br />

end;<br />

s3;<br />

end;<br />

s4; return z;<br />

end;<br />

53<br />

f 1 (i)= (c1, s1, ~c2, s3) i , ~c1, s4,<br />

^z<br />

with i=0,1,2,...<br />

f 2 (i)= (c1, s1, ~c2, s3) i-1 , c1, s1,<br />

c2, s2, ^y<br />

with i=1,2,3,...


54<br />

EXAMPLE 7-5 B Early return method bodies and their control flows.<br />

When does a method<br />

invocation <strong>st</strong>art?<br />

What happens upon<br />

method invocation?<br />

begin<br />

s1;<br />

return x;<br />

s2;<br />

s3;<br />

end;<br />

7.7 Method invocation<br />

This section describes (1) when a method is invoked, (2) what happens upon and during<br />

the invocation of a method, and (3) the difference between the invocation of a normal and<br />

an early return method.<br />

A method is invoked in one of the following cases:<br />

• if a Dispatch filter accepts a message which was passing the input filters and dispatches<br />

it to inner. This is possible for interface methods only;<br />

• if a message is sent to the pseudo variable inner. In this way, both interface methods<br />

and private methods can be invoked;<br />

• at in<strong>st</strong>ance creation time. The initial method is invoked in this way and in this way<br />

only.<br />

Upon invocation of a method, the local variables (temps) of the method are created fir<strong>st</strong>:<br />

every local variable is initialized with a in<strong>st</strong>ance of the class which was specified by the<br />

declaration of the variable. Note that the parameters of a method —the arguments of the<br />

message— have been passed by reference because all variables are object references in<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>. What happens next depends on whether the invoked method is a normal or an<br />

early return method.<br />

Figure 7-1 depicts those differences. An early return method creates a new thread 1 , while a<br />

normal method does not. The <strong>st</strong>art and the end of a thread are represented by an downward<br />

and an upward pointing triangle, respectively. The thread itself appears as a continuous or<br />

1. A thread is a sequence of messages which can execute concurrently with other threads. See section 10.3,<br />

page 75.<br />

Chapter 7: Methods<br />

begin<br />

if c<br />

then s1; return x;<br />

else s3; return y;<br />

end;<br />

s5; s6<br />

end;<br />

f 1 = s1, ^x, s2, s3 f 1 = c, s1, ^x, s5, s6<br />

f 2 = ~c, s3, ^y, s5, s6<br />

begin<br />

if c1<br />

then s1; return x;<br />

else<br />

s2;<br />

if c2<br />

then s3; return y;<br />

else s4; return z;<br />

end;<br />

s5;<br />

end;<br />

end;<br />

f 1 = c1, s1, ^x<br />

f 2 = ~c1, s2, c2, s3, ^y, s5<br />

f 3 = ~c1, s2, ~c2, s4, ^z, s5<br />

begin<br />

if c1<br />

then s1; return x;<br />

else<br />

s2;<br />

if c2<br />

then s3; return y;<br />

else s4; return z;<br />

end;<br />

end;<br />

s5;<br />

end;<br />

f 1 = c1, s1, ^x, s5<br />

f 2 = ~c1, s2, c2, s3, ^y, s5<br />

f 3 = ~c1, s2, ~c2, s4, ^z, s5<br />

begin<br />

if c<br />

then s1; return x;<br />

else s3; return y; s4<br />

end;<br />

s5; s6<br />

end;<br />

f 1 = c, s1, ^x, s5, s6<br />

f 2 = ~c, s3, ^y, s4, s5, s6<br />

begin<br />

while c<br />

begin<br />

s1; s2;<br />

end;<br />

s3;<br />

return x;<br />

s4;<br />

s5<br />

end;<br />

f(i)= (c, s1, s2) i , ~c, s3, ^x, s4,<br />

s5<br />

with i=0,1,2,...


dashed line, and a method as a rectangle. The figure below 2 shows two possible<br />

invocations of method m1 as the result of the so-called invoking message (obj.m1) which<br />

has been sent in the so-called invoking method m0.<br />

FIGURE 7-1 Invocation of a normal method and an early return method.<br />

Invocation of a<br />

normal method<br />

Invocation of an<br />

early return method<br />

Pseudo variables<br />

during the invocation<br />

normal early return<br />

method method<br />

m0 m0<br />

return x<br />

If m1 is a normal method, the <strong>st</strong>atements in the body of the method will be executed in the<br />

same thread in which the invoking message was sent. The <strong>st</strong>atements in the body are<br />

executed one after another until a return is executed (return x). Then, the invoking method<br />

(m0) continues with the <strong>st</strong>atement which follows the invoking message (obj.m1).<br />

For an early return method (shown right in figure 7-1) a new thread is created and the<br />

<strong>st</strong>atements of the method body are executed in this thread. The invoking method and its<br />

thread are blocked until the invoked method returns an object (return x). The invoking<br />

thread then resumes its execution: the remaining <strong>st</strong>atements of the invoking method are<br />

executed concurrently with the <strong>st</strong>atements following the return in the invoked method. The<br />

thread in this method ends when its la<strong>st</strong> <strong>st</strong>atement has been executed.<br />

Using an early return method, we can create a new, concurrent thread. Note that a new<br />

thread is created every time an early return method is invoked.<br />

During the invocation of the method, the pseudo variables refer to the following objects:<br />

• message: the invoking message. It is an in<strong>st</strong>ance of class ActiveMessage;<br />

• inner: the inner part of the executing object, i.e. without the encapsulating interface<br />

part, without the filters;<br />

• self: the executing object;<br />

• server: the object that originally received the invoking message;<br />

• sender: the object which has sent the invoking message.<br />

2. This figure shows two diagrams similar to the diagrams used in chapter 10. In the diagrams used here, we<br />

have omitted the passing of the message through the filters, but we do show the invoking method.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

obj.m1 obj.m1<br />

m1 m1<br />

Invoking Thread<br />

New Thread<br />

return x<br />

55


56<br />

7.8 Statements in a method body<br />

The <strong>st</strong>atements in the method body are separated by semicolons. It is possible to have an<br />

empty <strong>st</strong>atement, and thus also to have an empty method body. A <strong>st</strong>atement can further be<br />

an assignment (section 3.3.4), an expression (chapter 4), one of the control <strong>st</strong>ructures<br />

(chapter 5) or a return <strong>st</strong>atement (section 7.5). The syntax is as follows:<br />

<strong>st</strong>atements ::=<br />

<strong>st</strong>atement<br />

| <strong>st</strong>atements ; <strong>st</strong>atement<br />

<strong>st</strong>atement ::=<br />

assignmentStatement<br />

| messageExpression<br />

| operatorExpression<br />

| conditionalStatement<br />

| forStatement<br />

| whileStatement<br />

| returnStatement<br />

| // i.e. empty<br />

Chapter 7: Methods


8 Conditions<br />

A condition provides information about the current <strong>st</strong>ate of an object. It is a special kind of<br />

method that takes no parameters and returns a boolean result. Apart from conditions<br />

defined by the class self, so called local conditions, it is possible to reuse a condition from<br />

another class.<br />

A condition is declared at the interface part of a class (section 8.1), while the<br />

implementation of a local condition is defined in the implementation part (section 8.2).<br />

Note that the implementation of a reused condition is defined by the class it has been<br />

reused from. Section 8.3 describes the use of conditions.<br />

8.1 Condition declaration<br />

There are two forms of condition declaration, a reused condition and a local condition<br />

declaration. The reused condition defines the name of the condition and the object it is<br />

reused from. This object mu<strong>st</strong> be an external or an internal. The local condition declaration<br />

defines only its name, while its implementation is defined in the implementation part. It is<br />

not allowed that a condition and a method have the same name. The syntax of a condition<br />

declaration is shown below.<br />

conditionDeclarations ::=<br />

( conditions ( conditionDeclaration ; )* )?<br />

conditionDeclaration ::=<br />

localConditionDeclaration | reusedConditionDeclaration<br />

localConditionDeclaration ::=<br />

conditionName<br />

reusedConditionDeclaration ::=<br />

objectName . conditionName<br />

conditionName ::=<br />

identifier<br />

objectName ::=<br />

identifier<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

57


58<br />

We show the declaration of two local conditions in the example below. Class<br />

BoundedBuffer allows you to <strong>st</strong>ore and retrieve objects using the put and get method,<br />

respectively. The condition notFull represent the <strong>st</strong>ate in which the buffer is not full yet.<br />

The condition notEmpty describes the <strong>st</strong>ate in which the buffer contains at lea<strong>st</strong> one<br />

element. An object can be <strong>st</strong>ored in the buffer if the buffer is not full, while an object can<br />

be retrieved from it if the buffer is not empty. The conditions are used in the wait filter<br />

bufferSync to specify the synchronization of the buffer. Section 9.6.4 will discuss the wait<br />

filter in more detail.<br />

EXAMPLE 8-1 A class BoundedBuffer(limit : SmallInteger) interface<br />

conditions<br />

notFull;<br />

notEmpty;<br />

methods<br />

put(object : Any) returns nil;<br />

get returns Any;<br />

inputfilters<br />

bufferSync : Wait = {notFull => put, notEmpty => get};<br />

dispatching : Dispatch = {inner.*};<br />

end; // BoundedBuffer interface<br />

8.2 Condition implementation<br />

The implementation of conditions are defined in the conditions section of the<br />

implementation part of a class. The ordering of the conditions is not important: the<br />

conditions can be in a different order as they are declared at the interface part. The<br />

condition implementation has a similar <strong>st</strong>ructure as a method implementation. A comment<br />

and local variables can be defined, while the body can contain any <strong>st</strong>atement also allowed<br />

in the body of a method. The syntax of the condition implementation as follows:<br />

conditionImplementations ::=<br />

: ( conditions ( conditionImplementation ; )* )?<br />

conditionImplementation ::=<br />

: conditionName<br />

( comment <strong>st</strong>ring ; )?<br />

( temps ( objectDeclaration ; )* )?<br />

begin <strong>st</strong>atements end<br />

As an example of condition implementations, we continue with the implementation of<br />

class BoundedBuffer, shown below. The buffer <strong>st</strong>ores its elements in the in<strong>st</strong>ance variable<br />

<strong>st</strong>ore. The in<strong>st</strong>ance variables putpos and getpos hold the position in the array <strong>st</strong>ore where<br />

to <strong>st</strong>ore (method put) and retrieve (method get) the next object, respectively. Initially, they<br />

will both be at the fir<strong>st</strong> position, i.e. 1. The buffer is empty if putpos and getpos are the<br />

same. The buffer is full if the putpos is about to overtake the getpos, that is, if (limit +<br />

getpos - putpos) mod limit = 1. Note that the capacity (the maximum number of objects) of<br />

the buffer is limit - 1: the la<strong>st</strong> free position, in this particular implementation, is needed to<br />

be able to recognize the full <strong>st</strong>ate.<br />

The implementation of the notFull and notEmpty conditions are <strong>st</strong>raightforward: they are<br />

the logical negation of the formerly derived full and empty con<strong>st</strong>raints.<br />

EXAMPLE 8-1 B class BoundedBuffer implementation<br />

in<strong>st</strong>vars <strong>st</strong>ore : Array(limit); // index ranges from 1 to limit<br />

putpos, getpos : SmallInteger;<br />

conditions<br />

notFull<br />

begin<br />

return not((limit + getpos - putpos) mod limit = 1)<br />

Chapter 8: Conditions


end;<br />

notEmpty<br />

begin<br />

return not(putpos = getpos)<br />

end;<br />

initial<br />

begin putpos := 1; getpos := 1; end;<br />

methods<br />

put(object : Any)<br />

begin<br />

<strong>st</strong>ore.at:put:(putpos, object);<br />

putpos := putpos mod limit + 1<br />

end;<br />

get<br />

temps object : Any;<br />

begin<br />

object := <strong>st</strong>ore.at:(getpos);<br />

getpos := getpos mod limit + 1;<br />

return object<br />

end;<br />

end; // BoundedBuffer implementation<br />

8.3 Using a condition<br />

Condition invocation A condition is mainly invoked during the filtering of a message: a filter uses a conditions<br />

to decide to accept or reject the message. A condition, however, can also be invoked by its<br />

owner by sending a message to inner. This can be used for creating a condition which is a<br />

logical combination of other conditions and in a method to provide <strong>st</strong>ate information of the<br />

object. It is however not possible for objects to call a condition by sending a message to its<br />

owner.<br />

Pseudo variable<br />

message<br />

The notFull and notEmpty conditions of example 8-1 could be combined to provide a<br />

condition called partial which reflects the <strong>st</strong>ate if the BoundedBuffer in<strong>st</strong>ance is neither full<br />

nor empty. Its implementation can be defined as:<br />

partial<br />

begin return inner.notFul and inner.notEmpty end;<br />

The second use of invoking a condition is, for example, in a method printState of class<br />

BoundedBuffer which displays whether the buffer is full or not. This method could be<br />

defined as:<br />

printState<br />

begin<br />

if inner.notFull<br />

then self.print(’The buffer is not full’)<br />

else self.print(’The buffer is full’)<br />

end<br />

end;<br />

If a condition has been invoked during the filtering of a message, the pseudo variable<br />

message refers to this message. It can be used to examine the attributes of the filtered<br />

message. For in<strong>st</strong>ance, the condition ifYouAreAPo<strong>st</strong>man (example 9-4, page 68) te<strong>st</strong>s<br />

whether the sender of a message is a po<strong>st</strong>man, i.e. an in<strong>st</strong>ance of class Po<strong>st</strong>man. It could<br />

have been defined as<br />

conditions<br />

ifYouAreAPo<strong>st</strong>man<br />

begin return message.sender.class == Po<strong>st</strong>man end;<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

59


60<br />

If a condition has been invoked by sending a message to inner, the pseudo variable<br />

message refers to this message.<br />

Conditions mu<strong>st</strong> be side effect free: this means that the condition mu<strong>st</strong> not invoke local<br />

methods since this can lead to the release of blocked messages. The current compiler<br />

cannot check whether a condition is side effect free. It is therefore the responsibility of the<br />

programmer to provide such conditions.<br />

Finally a warning. Do not send a message to self, server or sender, in the condition body,<br />

as this can or, in case of a message to self, certainly leads to a deadlock situation. This is<br />

under<strong>st</strong>andable because the condition is evaluated while the message is filtered by the<br />

filtergroup. Only one message will be evaluated by a filtergroup at a time. Other arriving<br />

messages are blocked until the filtered message leaves the filtergroup. If a condition sends<br />

the aforementioned message, it waits forever for its reply.<br />

Chapter 8: Conditions


9 Filters<br />

This chapter discusses the various filter types and the filtering mechanism. Fir<strong>st</strong> it<br />

introduces some terminology and general concepts.<br />

9.1 Introduction<br />

Every class specifies a group of input filters and a group of output filters. A message sent<br />

to an object mu<strong>st</strong> pass the input filters, and a message sent by an object mu<strong>st</strong> pass its output<br />

filters. Every filter in the group of filters filter a message that passes it. This means that the<br />

filter determines whether it accepts or rejects the message, and then takes an accept or<br />

reject action, respectively. A filter accepts a message if it is accepted by one of the<br />

filterelements specified in the filterinitializer. The message is rejected if no filterelement<br />

can accept the message. The filterinitializer contains a number of filterelements. A<br />

filterelement consi<strong>st</strong>s of a condition and a messagepattern: it accepts a message if the<br />

condition is true and the message matches the messagepattern.<br />

The accept, c.q. reject action of a filter is determined by the filterhandler of the filter. The<br />

filterhandlers implemented in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> version 3.00 include Dispatch, Error, Send, Wait and<br />

Meta. A filter with such a handler is called a dispatch filter, an error filter, a send filter, a<br />

wait filter or a meta filter, respectively.<br />

EXAMPLE 9-1 class Stack interface<br />

...<br />

inputfilters<br />

<strong>st</strong>ackEmpty : Error = { <strong>st</strong>ackNotEmpty => pop, true ~> pop};<br />

invoke : Dispatch = { inner.pop, inner.push};<br />

...<br />

end; // Stack interface<br />

The example above shows a group of two input filters as part of the interface of class<br />

Stack. The filter called <strong>st</strong>ackEmpty is an error filter —its handler is Error— and its<br />

initializer contains two filterelements: <strong>st</strong>ackNotEmpty => pop and true ~> pop. If the <strong>st</strong>ack<br />

is not empty, this filter will accept a message with selector pop, since the fir<strong>st</strong> filterelement<br />

accepts such a message: the condition <strong>st</strong>ackNotEmpty evaluates to true and the selector of<br />

the message matches the messagepattern pop. The second filterelement true ~> pop is an<br />

exclusion filterelement. Such kind of filterelement will accept a message if the condition<br />

evaluates to true and the message does not match the message pattern. The exclusion<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

61


62<br />

Which messages pass<br />

the input filters?<br />

Which messages pass<br />

the output filters?<br />

element true ~> pop thus accepts messages that do not have a selector pop. The<br />

<strong>st</strong>ackEmpty error filter thus rejects a message pop if the <strong>st</strong>ack is not empty and accepts<br />

other messages. The accept action of an error filter causes the message to be offered to the<br />

following filter, while the reject action raises an error.<br />

The next filter is called invoke. This is a dispatch filter —its handler is Dispatch— which<br />

accepts a message with a selector pop (accepted by its fir<strong>st</strong> filterelement) or push (accepted<br />

by its second filterelement). The dispatch filter accept action dispatches the message to<br />

inner which causes the respective methods pop and push to be invoked. A message that is<br />

rejected by a dispatch filter is passed on to the next filter. If there are no further filters in the<br />

set, such as in this case, and a message has fallen through the la<strong>st</strong> filter, an error will be<br />

raised.<br />

9.2 Input and output filters<br />

Every object has a group of input filters and a group of output filters. This has been<br />

depicted in figure 9-1. A group of filters acts like a layered collection of sieves: a message<br />

is sieved by each filter in that group in turn, until a filter filters it out. If a message has<br />

passed all the filters in the group, —i.e. no filter has filtered it out— the object cannot<br />

handle the message and it will raise an error.<br />

The group of input filters determines how a message that is sent to the object containing<br />

them, is handled by that object. Every message that is sent to an object passes the group of<br />

input filters of that object. For in<strong>st</strong>ance, in figure 9-1, a message x.m(a1, ..., an) is sent to<br />

object x fir<strong>st</strong> passes the input filters of x. Suppose the input dispatch filter f3 of x accepts<br />

the message and delegates it to an object z which is an internal or external of x: the<br />

message then passes through the input filters of z.<br />

The group of output filters determines how a message that is sent by the object to another<br />

object is handled. Only a message sent to an object that lays outside the boundary of the<br />

sending object will pass the output filters of the sending object. That is, if an object sends a<br />

message to one of its externals, to self, server or sender, the message will pass the output<br />

filters. A message will not pass through the output filters if it is sent to the pseudovariable<br />

message, to an object manager ^self or ^server, to an internal or an in<strong>st</strong>ance variable of the<br />

object, or to a local variable of a method, but enters the input filters of the receiver of the<br />

message directly. A message sent to inner does not pass through the output filters either,<br />

but since inner is the object without filters, a method is invoked immediately.<br />

FIGURE 9-1 An object with input and output filters<br />

object x<br />

input filters of x<br />

internals of x<br />

output filters of x<br />

In figure 9-1, in a method of the object x message y.m2 is sent. If y is an external of x, the<br />

message passes the output filters of x, otherwise y is an internal or in<strong>st</strong>ance variable of x, or<br />

a local variable of the method and therefore the message enters the input filters of y<br />

directly.<br />

Chapter 9: Filters<br />

f1 : Error = {...}<br />

f2 : Wait= {...}<br />

f3 : Dispatch = {...}<br />

f4 : Wait = {...}<br />

f5 : Meta = {...}<br />

f6 : Send = {...}<br />

y.m2<br />

self.m3<br />

externals of x<br />

methods of x


A reused filter is bound<br />

at compile-time<br />

The group of input and output filters are declared in the class interface part, in the section<br />

<strong>st</strong>arting with the keywords inputfilters and outputfilters, respectively.<br />

inputfilters ::=<br />

inputfilters ( filterDeclaration ; )*<br />

outputfilters ::=<br />

outputfilters ( filterDeclaration ; )*<br />

9.3 Filterdeclaration<br />

There are two forms of filter declarations: the declaration of a local filter, an d the<br />

declaration of a reused filter. The former defines the filter handler and the filterinitializer<br />

self. The second form declares a filter that is reused from an external or internal object.<br />

This means that the filter handler and initializer is determined by the class of the external<br />

or internal object.<br />

9.3.1 Reused filter<br />

It is possible to reuse a filter from an other class with the reused filter declaration:<br />

filterDeclaration ::=<br />

objectName . filterName<br />

The objectName mu<strong>st</strong> be the name of an internal or external object. The filterName mu<strong>st</strong><br />

be a name of either a reused filter declaration or a local filter declaration of the object to<br />

which the objectName refers.<br />

The handler and the initializer are as that of the reused filter declaration. Objects (matching<br />

and sub<strong>st</strong>itution targets) and conditions that are referred to in the initializer are bound to<br />

those (in the scope) of the reusing object, i.e. not to those of the object from which the<br />

filter declaration is reused.<br />

In the current compiler version (version 3.00) only compile-time binding to the filter<br />

declaration is used. This means that if its handler or initializer changes (in class it is reused<br />

from) after an object that reused this filter has been compiled, this object is not updated<br />

with the new definition of the filter.<br />

9.3.2 Local filter<br />

With the local filter declaration, the class can specifies its name, handler and initializer:<br />

filterDeclaration ::=<br />

filterName : filterHandler = filterInitializer<br />

The filtername defines the name of the filter. The filterhandler defines the handler of the<br />

filter which mu<strong>st</strong> be on of Dispatch, Error, Wait, Send or Meta. The filterinitializer defines<br />

how a message is filtered by the filter.<br />

Filterinitializer The filterinitializer is comprised of at lea<strong>st</strong> one filterelement. Each filterelement determines<br />

if it accepts or rejects a message that passes through the filter. If a message is accepted by<br />

the filterelement, the message is accepted by the filter and its accept action will be carried<br />

out. If a message is rejected by a filterelement, the next filterelement (in declaration order,<br />

from left to right) will be consulted to see if that filterelement can accept the message. If no<br />

filterelement can accept the message, the message is rejected by the filter. In this case, its<br />

reject action will be carried out.<br />

filterInitializer ::=<br />

{ filterElement ( , filterElement )* }<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

63


64<br />

Filterelement A filterelement determines if it accepts or rejects a message that passes through the filter.<br />

There are two forms: an inclusionelement and an exclusionelement.<br />

The inclusionelement accepts a message if one of the conditions in the conditionset<br />

evaluates to true and the message matches one of the patterns in the messagepatternset.<br />

The exclusionelement, on the other hand, accepts a message if one of the conditions in the<br />

conditionset evaluates to true and the message does not match any of the patterns in the<br />

messagepatternset.<br />

EXAMPLE 9-2 mySync : Wait = {m1, {c1, c2}=>b.*, true~>{b.*, m2}};<br />

This example shows a wait filter which initializer has two inclusionElements and one<br />

exclusionElement. This filter would accept a message with selector m1 always, a message<br />

with a selector in the signature of b (see page 68) if either c1 or c2 is true, and a message<br />

with a selector that is not m2 and is not in the signature of b.<br />

filterElement ::=<br />

inclusionElement | exclusionElement<br />

inclusionElement ::=<br />

messagePattern | conditionSet => messagePatternSet<br />

exclusionElement ::=<br />

conditionSet ~> messagePatternSet<br />

Condition A condition referred to in a filterinitializer is has to be declared in the interface of the class.<br />

It can either be a reused condition or a condition implemented by the class itself. The<br />

condition true is also possible which evaluates always to true.<br />

conditionSet ::=<br />

condition | { condition ( , condition )* }<br />

condition ::=<br />

true | conditionName<br />

Messagepattern A messagepattern is used to match the selector or the target or both of the message. The<br />

matchingpattern and signaturepattern are the two forms possible.<br />

In the matchingpattern [a.b]c.d, the message mu<strong>st</strong> match with the matchingpart a.b, and if<br />

it does, the sub<strong>st</strong>itutionpart c.d will be returned as the result of the match. With the<br />

signaturepattern c.d, the message matches if the selector of the message is c and is<br />

included in the signature of d.<br />

messagePatternSet ::=<br />

messagePattern<br />

| { messagePattern ( , messagePattern )* }<br />

messagePattern ::=<br />

matchingPattern<br />

| signaturePattern<br />

matchingPattern ::=<br />

[ matchingPart ] sub<strong>st</strong>itutionPart<br />

matchingPart ::=<br />

messageSelector<br />

| objectName . messageSelector<br />

| *. messageSelector<br />

| self . messageSelector<br />

Chapter 9: Filters


sub<strong>st</strong>itutionPart ::=<br />

signaturePattern<br />

signaturePattern ::=<br />

messageSelector<br />

| objectName . messageSelector<br />

| *. messageSelector<br />

| inner . messageSelector<br />

| self . messageSelector<br />

messageSelector ::=<br />

selector | *<br />

9.3.3 Rewrite rules for filterelements<br />

Some parts of the filterelements can be omitted —for in<strong>st</strong>ance, the conditionset in an<br />

inclusionelement— while others have multiple parts, like the conditionset. By rewriting<br />

them using the following rules, one can derive equivalent filterinitializer which contains<br />

inclusionelements that have a single condition and a single messagepattern, and<br />

exclusionelements that have a single condition and either a single or a set of<br />

messagepatterns.<br />

The rewrite rules for filterelements are li<strong>st</strong>ed in the following table. The fir<strong>st</strong> rule shows<br />

that the default target is the wildcard. A missing condition in a filterelement implies the<br />

true condition (rule 2). Rules 3 to 6 show that (set of) messagepattern(s) is di<strong>st</strong>ributed over<br />

the elements of a set of conditions. In the la<strong>st</strong> rule, a single condition is di<strong>st</strong>ributed over the<br />

elements of a set of messagepatterns.<br />

TABLE 9-1 Rewrite rules for filterelements<br />

Filterelement Filterelement after rewrite<br />

1 sel *.sel<br />

2 mp true=>mp<br />

3 {c1 , c2 , ..., cn }=>mp c1 =>mp, ..., cn =>mp<br />

4 {c1 , c2 , ..., cn }=>{mp1 , ..., mpp } c1 =>{mp1 , ..., mpp }, ..., cn =>{mp1 , ..., mpp }<br />

5 {c1 , c2 , ..., cn }~>mp c1 ~>mp..., cn ~>mp<br />

6 {c1 , c2 , ..., cn }~>{mp1 , ..., mpp } c1 ~>{mp1 , ..., mpp }, ..., cn ~>{mp1 , ..., mpp }<br />

7 c=>{mp1 , mp2 , ..., mpp } c=>mp1 , c=>mp2 , ..., c=>mpp Note that there exi<strong>st</strong>s no rule that di<strong>st</strong>ributes a set of conditions over a set of<br />

messagepatterns. The filterelement {c 1 , c 2 , ..., c n }=>{mp 1 , ..., mp p } is therefore not<br />

equivalent to {c 1 , c 2 , ..., c n }=>mp 1 , ..., {c 1 , c 2 , ..., c n }=>mp p . Neither is the filterelement<br />

{c 1 , c 2 , ..., c n }~>{mp 1 , ..., mp p } equivalent to {c 1 , c 2 , ..., c n }~>mp 1 , ..., {c 1 , c 2 , ...,<br />

c n }~>mp p .<br />

EXAMPLE 9-3 The following four filterdeclarations are equivalent to each other by using the rules 1, 4<br />

and 7, respectively.<br />

defSync1 : Wait = { {free, recursive}=>{m3, inner.*}, true~>inner.*};<br />

defSync2 : Wait = { {free, recursive}=>{*.m3, inner.*}, true~>inner.*};<br />

defSync3 : Wait = { free=>{*.m3, inner.*}, recursive=>{*.m3, inner.*}, true~>inner.*};<br />

defSync4 : Wait = { free=>*.m3, free=>inner.*, recursive=>*.m3, recursive=>inner.*,<br />

true~>inner.*};<br />

But they are not equivalent to<br />

defSync5 : Wait = { {free, recursive}=>*.m3, {free, recursive}=>inner.*, true~>inner.*};<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

65


66<br />

9.4 Filtering a message<br />

This section describes the filtering of a message in detail. The filtering process of a<br />

message is made up of the <strong>st</strong>eps shown below. The filterelement accept te<strong>st</strong> of <strong>st</strong>eps 4 to 8<br />

have been combined in table 9-2 for an inclusionelement and in table 9-3 for an<br />

exclusionelement. The signature of an object which is referred to in <strong>st</strong>ep 5b is defined in<br />

section 9.5.<br />

1. filtering through the group of filters.<br />

The message is offered to each filter in the group in turn, <strong>st</strong>arting with the fir<strong>st</strong>, to filter<br />

it. If the filter did not sift it out, it will be offered to the next filter. If the la<strong>st</strong> filter in the<br />

group has not filtered it out, an error will be raised: ‘Input filters didn’t filter out message<br />

M’ or ‘Output filters didn’t filter out message M’ if the message “fell through” all the<br />

input filters or output filters, respectively.<br />

A message will have been sifted out if either (a) an error occurred (error filter), or (b)<br />

the message received a reply. The latter is the case if the message eventually lead to the<br />

the invocation of a method (dispatch filter), or during the reification of the message, a<br />

reply was supplied for it (meta filter)<br />

Only one message is allowed to pass through the filtergroup at a time. If a message<br />

would like to pass the filtergroup while another is already being filtered by it, the<br />

message waits until the other message has left the group;<br />

2. filtering by a filter.<br />

If a filter is offered a message to filter, it mu<strong>st</strong> decide to accept or to reject the message.<br />

This is called the filter accept te<strong>st</strong> of the message. If the filter rejects the message, its<br />

reject action is carried out. Otherwise the filter accepts the message and its accept<br />

action is carried out.<br />

What the accept and reject actions actually involve, depends on the filter handler. They<br />

will be described in the section 9.6.<br />

If the filter accepts the message, a new target object and a new selector becomes<br />

available, which some filters ignore (wait filter), some sub<strong>st</strong>itute them in the message<br />

(error, dispatch and send filter) and others use it as the receiver and selector of a new<br />

message (meta filter);<br />

3. the filter accept te<strong>st</strong>.<br />

The message is offered to each filterelement of the its initializer in turn, <strong>st</strong>arting with<br />

the left-mo<strong>st</strong>, to te<strong>st</strong> if the filterelement accepts it. If it does so, the filter will accept the<br />

message, otherwise the message offered to the next-right filterelement. If none of the<br />

filterelements in the filterinitializer accepts the message, the filter rejects the message.<br />

4. the filterelement accept te<strong>st</strong>.<br />

There are two kinds of filterelements: the inclusionelement C=>M and the<br />

exclusionelement C~>M or C~>{M1 , ... ,Mn }, in which C is a condition and M, M1 , ...<br />

,Mn are messagepatterns.<br />

a) The inclusion filterelement C=>M accepts a message if the condition C evaluates to<br />

true and the message matches messagepattern M.<br />

b) The exclusion filterelement C~>M accepts a message if the condition C evaluates to<br />

true and the message does not match messagepattern M.<br />

c) The exclusion filterelement C~>{M1 , ... ,Mn } accepts a message if the condition C<br />

evaluates to true and the message does not match any of the messagepatterns M1 , ...<br />

,Mn .<br />

5. messagepattern matching.<br />

There are two kinds of messagepatterns: the matchingpattern [mt.ms]<strong>st</strong>.ss and the<br />

signaturepattern mt.ms, in which mt is the matching target, ms the matching selector,<br />

<strong>st</strong> the sub<strong>st</strong>itution target and ss the sub<strong>st</strong>itution selector.<br />

a) A message matches the matchingpattern [mt.ms]<strong>st</strong>.ss if the receiver rcv of the<br />

message matches with the target mt, and if the selector sel of the message matches with<br />

the matching selector ms.<br />

Chapter 9: Filters


No target and selector<br />

returned by an<br />

exclusionelement<br />

b) A message matches the signaturepattern mt.ms if the message matches with the<br />

signature of target mt, and the selector sel of the message matches with the selector<br />

ms.<br />

6. matching the receiver rcv of the message with targetobject mt.<br />

If mt is the wildcard then the receiver rcv matches, otherwise the rcv matches with mt if<br />

and only if the rcv is the same object as mt refers to.<br />

7. matching the selector sel of the message with selector ms.<br />

If ms is the wildcard then the message matches, otherwise the message matches if and<br />

only if its selector sel is ms.<br />

8. matching with the signature of mt.<br />

If mt is the wildcard then the message matches, otherwise the message matches if and<br />

only if the signature of the object to which mt refers includes the selector sel.<br />

The table below li<strong>st</strong>s the accept conditions (<strong>st</strong>eps 4a, 5-8) for all possible inclusion<br />

filterelements.<br />

TABLE 9-2 Inclusionelement accept condition for a message m<br />

filterelement<br />

accept condition<br />

target<br />

return<br />

ed<br />

select<br />

orretu<br />

rned<br />

Table 9-3 below li<strong>st</strong>s the accept conditions (<strong>st</strong>eps 4b, 4c, 5-8) for the mo<strong>st</strong> of possible<br />

exclusion filterelements. In this table, •.• denotes either c.d, c.*, *.d or *.*. The left column<br />

shows filterelements C~>M with a single message pattern M, while the right column shows<br />

a filterelement C~>{M 1 ,M 2 , ...} with a set of message patterns M 1 , M 2 , ....<br />

Note that an exclusionelement does not return a target or selector if the message matches<br />

it.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

filterelement<br />

accept condition<br />

target<br />

return<br />

ed<br />

C=>[a.b]c.d C ∧ m.rcv = a ∧ m.sel = b c d C=>[b] d C ∧ m.sel = b - d<br />

C=>[a.b] c.* C ∧ m.rcv = a ∧ m.sel = b c - C=>[b] *.* C ∧ m.sel = b - -<br />

C=>[a.b] *.d C ∧ m.rcv = a ∧ m.sel = b - d C=>[b] * C ∧ m.sel = b - -<br />

C=>[a.b] d C ∧ m.rcv = a ∧ m.sel = b - d C=>[*.*] c.d C c d<br />

C=>[a.b] *.* C ∧ m.rcv = a ∧ m.sel = b - - C=>[*.*] c.* C c -<br />

C=>[a.b] * C ∧ m.rcv = a ∧ m.sel = b - - C=>[*.*] *.d C - d<br />

C=>[a.*] c.d C ∧ m.rcv = a c d C=>[*.*] d C - d<br />

C=>[a.*] c.* C ∧ m.rcv = a c - C=>[*.*] *.* C - -<br />

C=>[a.*] *.d C ∧ m.rcv = a - d C=>[*.*] * C - -<br />

C=>[a.*] d C ∧ m.rcv = a - d C=>[*] c.d C c d<br />

C=>[a.*] *.* C ∧ m.rcv = a - - C=>[*] c.* C c -<br />

C=>[a.*] * C ∧ m.rcv = a - - C=>[*] *.d C - d<br />

C=>[*.b] c.d C ∧ m.sel = b c d C=>[*] d C - d<br />

C=>[*.b] c.* C ∧ m.sel = b c - C=>[*] *.* C - -<br />

C=>[*.b] *.d C ∧ m.sel = b - d C=>[*] * C - -<br />

C=>[*.b] d C ∧ m.sel = b - d C=>c.d C ∧ m.sel = d ∧ d ∈ sig(c) c d<br />

C=>[*.b] *.* C ∧ m.sel = b - - C=>c.* C ∧ m.sel ∈ sig(c) c -<br />

C=>[*.b] * C ∧ m.sel = b - - C=>*.d C ∧ m.sel = d - d<br />

C=>[b] c.d C ∧ m.sel = b c d C=>d C ∧ m.sel = d - d<br />

C=>[b] c.* C ∧ m.sel = b c - C=>*.* C - -<br />

C=>[b] *.d C ∧ m.sel = b - d C=>* C - -<br />

67<br />

select<br />

orretu<br />

rned


68<br />

Do not specify an<br />

exclusionelement<br />

containing the wildcard<br />

pattern *.*<br />

Note also, that if an exclusionelement contains the wildcard pattern *.*, a message will<br />

never be accepted by it. It is therefore useless to specify an exclusionelement containing<br />

such a wildcard pattern, like C~>[*.*]•.•, C~>*.*, C~>{..., [*.*]•.•, ...} or C~>{..., *.*, ...}.<br />

TABLE 9-3 Exclusionelement accept condition for a message m<br />

filterelement<br />

accept condition<br />

9.5 The signature of an object<br />

The signature of an object is the set of message selectors that the object would accept if all<br />

the conditions in the input filters, and in the input filters only, would be true.<br />

DEFINITION 9-1 The signature of an object<br />

a. The signature of inner is the set of selectors of the interface methods.<br />

b. The signature of a <<strong>st</strong>rong>Sina</<strong>st</strong>rong> object a set which includes<br />

1)the non-wildcard matchingselectors ms of the matchingpatterns<br />

[mt.ms]<strong>st</strong>.ss of the input filters which perform sub<strong>st</strong>itution on the<br />

message.<br />

2)the signatures of the objects mt in the signaturepatterns mt.ms of the<br />

input filters which perform sub<strong>st</strong>itution on the message.<br />

c. The signature of a Smalltalk object is the set of selectors of the methods defined by its<br />

class and superclasses.<br />

To be specific: the signature of a <<strong>st</strong>rong>Sina</<strong>st</strong>rong> object is a set that includes (1) the selectors of the<br />

interface methods, (2) the non-wildcard matching selectors of matchingpatterns of input<br />

Error filters, (3) the non-wildcard matching selectors of matchingpatterns of input Dispatch<br />

filters, and (4) the signatures of the objects in signaturepatterns in input Dispatch filters.<br />

As an example of the signature of an object, consider the class Mailbox below, in which<br />

anyone can <strong>st</strong>ore a letter and only ifYouAreAPo<strong>st</strong>man you can retrieve letters from it and<br />

access the box itself. The signature of an in<strong>st</strong>ance of Mailbox consi<strong>st</strong>s of the selectors<br />

putLetter, getLetters (the interface methods), emptyBox (matching selectors of the Error<br />

filter) and all the selectors defined by the object box (signature of box in Dispatch filter).<br />

EXAMPLE 9-4 class Mailbox interface<br />

internals<br />

box : Letterbox;<br />

conditions<br />

ifYouAreAPo<strong>st</strong>man;<br />

methods<br />

putLetter(aLetter : Letter) returns nil;<br />

getLetters returns Letters;<br />

inputfilters<br />

error : Error = { [emptyBox]getLetters, inner.*, box.*};<br />

Chapter 9: Filters<br />

target<br />

return<br />

ed<br />

select<br />

orretu<br />

rned<br />

filterelement<br />

accept condition<br />

target<br />

return<br />

ed<br />

C~>[a.b]•.• C ∧ (m.rcv ≠ a ∨ m.sel ≠ b) - - C~>{ [a.b]•.•, C ∧ (m.rcv ≠ a ∨ m.sel ≠ b) - -<br />

C~>[a.*]•.• C ∧ m.rcv ≠ a - - [a.*]•.•, ∧ m.rcv ≠ a<br />

C~>[*.b]•.• C ∧ m.sel ≠ b - - [*.b]•.•, ∧ m.sel ≠ b<br />

C~>[*.*]•.• false - - [*.*]•.•, ∧ false<br />

C~>c.d C ∧ (m.sel ≠ d ∨ d ∉ sig(c)) - - c.d, ∧ (m.sel ≠ d ∨ d ∉ sig(c))<br />

C~>c.* C ∧ m.sel ∉ sig(c) - - c.*, ∧ m.sel ∉ sig(c)<br />

C~>*.d C ∧ m.sel ≠ d - - *.d, ∧ m.sel ≠ d<br />

C~>*.* false - - *.*, ...} ∧ false ∧ ...<br />

select<br />

orretu<br />

rned


end;<br />

delegate : Dispatch = { ifYouAreAPo<strong>st</strong>man => {inner.getLetters, box.*},<br />

inner.putLetter};<br />

9.6 Filterhandlers<br />

In this section we describe the various filterhandlers. The filterhandlers implemented in<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> version 3.00 include Dispatch, Error, Send, Wait and Meta. Table 9-4 summarizes<br />

the accept action (left) and reject action (right) of each filterhandler. We have indicated if<br />

the filter performs the sub<strong>st</strong>itution of a new target and selector on the filtered message or if<br />

it discards them. For each filtertype it is further marked whether it can be used as an input<br />

filter, as an output or both.<br />

TABLE 9-4 Filter handler accept action and reject action.<br />

Dispatch Sub<strong>st</strong>itutions on message Input<br />

The new target and new selector are sub<strong>st</strong>ituted to the accepted message, if The message continues in the next<br />

they are defined;<br />

If the receiver of the message became is inner, the method with the same<br />

selector as the message will be invoked;<br />

Otherwise the message will be offered for filtering to the input filters of the<br />

receiver of the message.<br />

filter.<br />

Error Sub<strong>st</strong>itutions on message Input Output<br />

The new target and new selector are sub<strong>st</strong>ituted in the accepted message, if Raises the error ‘Reject in ErrorFilter<br />

they are defined;<br />

X::f of M’, where X is the class in which<br />

Then the message continues in the next filter.<br />

this error filter f is defined and M is a<br />

representation of the message.<br />

Send Sub<strong>st</strong>itutions on message Output<br />

The new target and new selector are sub<strong>st</strong>ituted to the accepted message, if The message continues in the next<br />

they are defined;<br />

If its owning object has no encapsulating object, or if the receiver of the<br />

message lies inside its encapsulating object, the message will be offered to<br />

the input filters of the receiver of the message. Otherwise the message is<br />

offered to the output filters of the encapsulating object.<br />

filter.<br />

Wait Sub<strong>st</strong>itutions discarded Input Output<br />

The message continues in the next filter. Note that no sub<strong>st</strong>itution are The message is blocked, i.e. execution<br />

carried out.<br />

of the calling thread is suspended until<br />

the condition on which the message<br />

blocked becomes true;<br />

Then the message continues in the next<br />

filter.<br />

Meta Used for message to ACT Input Output<br />

The execution of the calling thread is suspended;<br />

The message continues in the next<br />

The accepted message is reified and becomes an in<strong>st</strong>ance of the class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message;<br />

A new thread is created which sends a message with the new selector and<br />

the reified message as argument to the new target. This message does not<br />

pass through the output filters of the owning object but is offered to the<br />

input filters of the new target directly;<br />

The sending thread remains suspended until the reified message is dereified<br />

—this is if it receives a send, reply, fire or continue message;<br />

If the, now active message has a reply —if the reified form was reactivated<br />

with a reply message— it will not carry on in the next filter but return the<br />

reply to the sender. Otherwise it will be filtered by the following filter.<br />

filter.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

69


70<br />

9.6.1 Dispatch filter<br />

A dispatch filter can be used for inheritance and delegation. By declaring a dispatch filter<br />

which dispatches to the appropriate internal or external we can accomplish inheritance and<br />

delegation, respectively. Though dispatching a message to an internal object can be seen as<br />

inheritance, and dispatching to an external object as delegation, there is no di<strong>st</strong>inction<br />

between those two: a dispatch filter dispatches a message to another object.<br />

By specifying more target objects, we can accomplish multiple inheritance, cq. delegation.<br />

The left to right ordering in the filterinitializer resolves any name conflicts resulting from<br />

multiple inheritance.<br />

In [Bergmans94a] and [Bergmans94b] it is further shown how the dispatch filter can be<br />

used for dynamic inheritance and delegation.<br />

As an example of the dispatch filter, consider the class Manager below. The dispatch filter<br />

inheritAndDelegate specifies that this class inherits from class Employee and further<br />

delegates messages to the external DepartmentSecretary. If both the classes Employee<br />

and Secretary support the method name, then the name method of Employee would be<br />

invoked, because it is the fir<strong>st</strong> target in the dispatch filter.<br />

class Manager interface<br />

externals DepartmentSecretary : Secretary;<br />

internals empl : Employee;<br />

...<br />

inputfilters<br />

inheritAndDelegate : Dispatch = {employee.*, DepartmentSecretary.*};<br />

end;<br />

9.6.2 Error filter<br />

An error filter can be applied for checking incoming messages, multiple views and<br />

preconditions. In the Stack class (example 2-1A) we have seen the use of an error filter for<br />

checking messages. The use of the error filter for multiple views and preconditions has<br />

been described in [Aksit92], [Bergmans94a] and [Bergmans94b].<br />

9.6.3 Send filter<br />

A send filter can only be used as output filter for delivering a message to its receiver. If no<br />

output filters are declared for a class, a send filter is inserted automatically by the compiler.<br />

9.6.4 Wait filter<br />

A wait filter can be used for synchronizing messages. A message which is rejected by a<br />

wait filter is blocked until the message would be accepted by the wait filter.<br />

Synchronization con<strong>st</strong>raints are specified as the conditions in the initializer of a wait filter.<br />

As an example, consider the class BoundedBuffer which allows you to <strong>st</strong>ore and retrieve<br />

objects using the put and get method, respectively. An object can be <strong>st</strong>ored in the buffer if<br />

the buffer is not full, while an object can be retrieved from it if the buffer is not empty.<br />

These synchronization con<strong>st</strong>raints are specified by the wait filter bufferSync: a put message<br />

will be blocked if the notFull condition evaluates to false. A get message will be blocked if<br />

the notEmpty condition evaluates to false.<br />

EXAMPLE 9-5 class BoundedBuffer(limit : SmallInteger) interface<br />

conditions<br />

notFull;<br />

notEmpty;<br />

methods<br />

put(object : Any) returns nil;<br />

get returns Any;<br />

Chapter 9: Filters


Consecutive wait filters<br />

evaluated as if they are a<br />

single wait filter<br />

inputfilters<br />

bufferSync : Wait = {notFull => put, notEmpty => get};<br />

dispatching : Dispatch = {inner.*};<br />

end; // BoundedBuffer interface<br />

The implementation of the BoundedBuffer (shown in example 8-1 B, page 58), e<strong>st</strong>ablishes<br />

that after a get message the condition notFull becomes true thus releasing a blocked put<br />

message. A put message changes the condition notEmpty to true, thus releasing a blocked<br />

get message.<br />

There is one additional rule which applies to wait filters and to wait filters only.<br />

Subsequent wait filters in the filtergroup (input filters or output filters) are evaluated as if<br />

they were a single wait filter having conditions which are combined from every wait filter<br />

with an and. This has the effect that con<strong>st</strong>raints by earlier wait filters are not forgotten. A<br />

message will not be blocked if all the conditions in these consecutive filters evaluate to<br />

true. If there is at lea<strong>st</strong> one condition which is false, it will be blocked. The message is<br />

allowed to resume if all the conditions of the consecutive wait filters are true.<br />

Consider for example the input filters of the class MemBuffer which allocates memory to<br />

<strong>st</strong>ore elements.<br />

class MemBuffer interface<br />

...<br />

inputfilters<br />

memorySync : Wait = {memAvail => put, true => get};<br />

bufferSync : Wait = {notFull => put, notEmpty => get};<br />

dispatching : Dispatch = {inner.*};<br />

end;<br />

The two wait filters are evaluated as if they had been the single wait filter<br />

sync : Wait = {memAvail and notfull => put, true and notEmpty => get};<br />

9.6.5 Meta filter<br />

A meta filter is used for reflection on object interactions. Chapter 10 will discuss this filter<br />

type and its application more elaborately. The background of the meta filter can be found<br />

in [Aksit93].<br />

That concludes the discussion of the filters and the filtering of a message.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

71


72<br />

Chapter 9: Filters


Ab<strong>st</strong>ract<br />

Communication Type<br />

10 Message passing<br />

semantics<br />

This chapter describes what can happen if an object sends a message to another object. The<br />

fir<strong>st</strong> section explains the two <strong>st</strong>eps of message execution: filtering and method invocation.<br />

Section 10.2 discusses how a message and its attributes can be accessed during its<br />

execution.<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>, a message can execute concurrently with other messages. Concurrent executing<br />

messages are described by the notion called thread. This is the subject of section 10.3.<br />

During the filtering of a message, a meta filter can reify the message. Message reification<br />

allows an object to reflect on message communication between objects. Section 10.4<br />

describes the process of message reification. An object which is able to reflect on —to<br />

ab<strong>st</strong>ract— message communication is known by the term ab<strong>st</strong>ract communication type, or<br />

ACT [Aksit89][Aksit93]. An ACT object can use reflection on message communication<br />

for con<strong>st</strong>raint checking and controlling object interactions.<br />

The la<strong>st</strong> section in this chapter reveals how the attributes of a reified message can be<br />

accessed and changed.<br />

10.1 Sending a message<br />

An object can reque<strong>st</strong> a service from another object by sending a message to it. Message<br />

passing in the composition filters object model follows the reque<strong>st</strong>/reply model: after a<br />

client object has sent a message —the reque<strong>st</strong>— to a server object, the client object waits<br />

until it receives a return value for the message —the reply— from the server object.<br />

The server object is entirely responsible for servicing the reque<strong>st</strong>: it can decide to handle<br />

the reque<strong>st</strong> itself (by executing some method), to delegate the reque<strong>st</strong> to another object, or<br />

even to reject it.<br />

In the Composition Filters Object Model, and thus also in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>, the execution of the<br />

message involves two <strong>st</strong>eps:<br />

• fir<strong>st</strong>, the message is filtered by filters.<br />

If the message leaves the object boundary of the sending object1 , the message will pass<br />

through the output filters of the sending object. Then, the message passes through the<br />

input filters of the server object. This object can decide (by the use of a dispatch filter)<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

73


74<br />

to delegate the message to another object where it is filtered by the input filters of that<br />

object.<br />

• eventually, a method is invoked.<br />

The method is invoked if there is a dispatch filter which dispatches the message to<br />

inner.<br />

Those two <strong>st</strong>eps are depicted in the diagram of figure 10-1. Similar message execution<br />

diagrams are used in the re<strong>st</strong> of this chapter.<br />

FIGURE 10-1 Execution of a message<br />

Reque<strong>st</strong><br />

m1<br />

In such a message execution diagram, time increases towards the bottom. The <strong>st</strong>art of the<br />

message execution, i.e. the issue of a message reque<strong>st</strong>, is indicated by a left pointing<br />

triangle . The message passes through the filters, shown by grey rectangles . In the<br />

figure above, we have indicated four filters: two wait filters (W) and two dispatch filters<br />

(D). The la<strong>st</strong> filter invokes a method2 , m1 in this case, which is represented by the larger,<br />

white rectangle. The message execution ends when the invoked method returns an object<br />

(return x): this reply on the message has been denoted by a right pointing triangle .<br />

Active message We will call a message which is being executed, an active message. We can refer to an<br />

active message by the pseudo variable message. We explain more on this in the following<br />

section.<br />

Thread After the execution of a message has ended, the following message is executed in a similar<br />

way: it is filtered and it invokes a method. The invocation of the method, the white<br />

rectangle in the figure above, consi<strong>st</strong>s of a sequence of message executions on its own. If<br />

we magnify the white rectangle, we could see several message executions one after<br />

another, each of them consi<strong>st</strong>ing of filtering and method invocation again 3 . A sequence of<br />

such message executions is called a thread. The thread will be the topic of section 10.3.<br />

1. This is the case if the message is sent to an external of the sending object, or to the pseudo variables self,<br />

server or sender. A message to an internal, an in<strong>st</strong>ance variable, a class parameter, a method parameter or<br />

local variable, or to the pseudo variables message or inner, does not pass the output filters, but enters the<br />

input filters of the server object directly.<br />

2. This is a dispatch filter. A dispatch filter invokes a method m1 if its filterinitializer contains a filter element<br />

like inner.* or inner.m1.<br />

3. Where would this end, you might ask. There are some methods that do not send other messages: they<br />

implement primitive operations such as the addition of two numbers.<br />

Chapter 10: Message passing semantics<br />

W<br />

D<br />

W<br />

D<br />

return x<br />

Filtering<br />

Method Invocation<br />

Thread Reply


10.2 The pseudo variable message and class ActiveMessage<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>, the pseudo variable message represents the active message which is an in<strong>st</strong>ance<br />

of the class ActiveMessage. Inside a method, message refers to the message that lead to<br />

the invocation of that method. Since condition evaluation is part of the message filtering<br />

process, the pseudo variable message inside a condition refers to the message that is<br />

currently being filtered.<br />

TABLE 10-1 Accessing the attributes of message.<br />

message.selector Returns a String which is the selector of the message.<br />

message.numArgs Returns a SmallInteger, indicating the number of arguments<br />

of the message.<br />

message.args Returns an Array containing the arguments.<br />

message.argsAt(n) Returns the nth argument.<br />

message.sender Returns the sender of the message. In a method, this object is<br />

also available through the pseudo variable sender.<br />

message.server Returns the server of the message. In a method, this object is<br />

also available through the pseudo variable server.<br />

message.receiver Returns the receiver of the message.<br />

message.isRecursive Returns true if the message is sent to self, server, or sender<br />

By sending the appropriate messages to the pseudo variable message, we can access the<br />

attributes of an active message. The attributes of a message include:<br />

• its selector;<br />

• its arguments;<br />

• the sender: the object which has sent the message;<br />

• the server: the object which has received the message fir<strong>st</strong>;<br />

• and its receiver: the object which has received the message at this moment. Initially,<br />

this attribute is the same as the server, but it becomes another object if a dispatch filter<br />

dispatches the message to that object.<br />

Recursive message An active message is defined as recursive if the message is sent to the pseudo variable self,<br />

server or sender. This is used by the default synchronization wait filter (page 41) to allow<br />

such messages to pass.<br />

The attributes of an active message can be retrieved, but they cannot be changed. The<br />

messages that can be sent to an in<strong>st</strong>ance of class ActiveMessage have been li<strong>st</strong>ed in<br />

appendix A.2, page 148. In table 10-1 however, we have indicated the messages often used<br />

to access the active message.<br />

10.3 Concurrency with threads<br />

A thread is a sequence of message executions. In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong>, any number of threads can be<br />

created and exi<strong>st</strong> at the same time. In this way, messages (and methods) can execute<br />

concurrently. Note that more than one thread can be active —executing concurrently—<br />

inside the same object: there are two or more methods which have been invoked and which<br />

are executing. If this is not desired, the object mu<strong>st</strong> have defined mutual exclusion with the<br />

aid of an input wait filter 4 .<br />

4. The <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> compiler inserts by default for every class an input wait filter that realizes mutual exclusion (see<br />

section 6.1.3, page 41). The programmer can override this, and define a more complex synchronization<br />

scheme for the class or no synchronization at all.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

75


76<br />

Creating concurrency There are two occasions in which a new thread is created and <strong>st</strong>arted:<br />

• upon the invocation of an early return method (see section 7.6, page 50, for the<br />

difference between a normal and an early return method),<br />

• when a message is sent to an ACT, upon the reification of a message by a meta filter.<br />

A thread ends when the la<strong>st</strong> message of that thread has been executed: it is the la<strong>st</strong><br />

message of either an early return method or of the ACT method. Note that if such a method<br />

contains an infinite loop, the thread will never finish.<br />

In diagrams, the <strong>st</strong>art of a new thread is represented by the downward pointing triangle<br />

( ). The end of a thread is depicted by an upward pointing triangle ( ).<br />

The left diagram of figure 10-2 shows that a normal (non-early return) method is executed<br />

in the same thread: the message a.m1 is filtered and the method m1 is invoked. After<br />

method m1 has returned an object (return x), the next message (b.m2) is filtered and<br />

method m2 is invoked.<br />

The middle diagram shows the execution of an early return method m3. The message a.m3<br />

is filtered as usual. After the la<strong>st</strong> filter, a dispatch filter, a new thread is created for the<br />

execution of method m3: The original thread is blocked until method m3 returns an object<br />

x. The message now has a reply and the blocked thread (the dashed line ) resumes by<br />

executing the next message, b.m4. After the method has returned a reply, the re<strong>st</strong> of m3<br />

(the messages following the return) is executed concurrently with the original thread, and<br />

thus with message b.m4. The new thread ends when the la<strong>st</strong> message in the early return<br />

method m3 has been executed.<br />

FIGURE 10-2 Single thread (left) and new concurrent threads (middle and right).<br />

normal early return<br />

message<br />

method method reification<br />

a.m1 a.m3 a.m5<br />

m1<br />

D D<br />

A new thread is also be created upon the reification of a message by a meta filter (the right<br />

mo<strong>st</strong> diagram in figure 10-2). Message reification and dereification is explained in the next<br />

section. For now, we can see that the message act.mAct executes in the new thread<br />

concurrently with method m5 in the original thread.<br />

Chapter 10: Message passing semantics<br />

M<br />

act.mAct<br />

return x return x<br />

msg.continue<br />

b.m2 b.m4<br />

m2<br />

D<br />

Original Thread<br />

New Thread<br />

D<br />

m3<br />

m4 m5<br />

b.m6<br />

m6<br />

D<br />

return x<br />

D<br />

mAct<br />

D<br />

return y


10.4 Message reification and dereification<br />

Message reification is the process of converting an active message into a fir<strong>st</strong>-class object,<br />

a so called reified message. The opposite process is called dereification and converts a<br />

reified message back into an active message. Reification suspends the execution of a<br />

message, while dereification reactivates it. A reified message is an in<strong>st</strong>ance of the class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message and, as we have seen in section 10.2, an active message is an in<strong>st</strong>ance of<br />

class ActiveMessage.<br />

The reification process takes place in a meta filter: if a meta filter accepts a message, it will<br />

reify the message. Then, the meta filters offers the reified message to an ab<strong>st</strong>ract<br />

communication type (ACT) object [Aksit93]. The ACT object is an arbitrary internal or<br />

external object, that is, it is an in<strong>st</strong>ance of some <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> class.<br />

A reified message will be reactivated if it receives one of the dereification messages<br />

continue, reply or send. The ACT object is responsible for sending one of these messages<br />

to the reified message (figure 10-3).<br />

FIGURE 10-3 Reification and dereification of a message.<br />

10.4.1 Message reification<br />

Reification of messages is realized in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> by a meta filter. This is the only location<br />

where active messages can be reified. If an active message is accepted by a meta filter, it<br />

will be reified —become an in<strong>st</strong>ance of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message— and used as the single<br />

argument of a new message. The new message and its receiver (an ACT object) are<br />

specified as the sub<strong>st</strong>itution part of a filterelement in the filterinitializer of that meta filter.<br />

A new thread is created and then this message is sent to the ACT. The thread of the<br />

original, but now reified message is blocked until the ACT dereifies the message.<br />

We illu<strong>st</strong>rate this with an example. Consider, for in<strong>st</strong>ance, the meta filter divcheck of the<br />

class NumericProcessor below. This class provides the <strong>st</strong>andard arithmetic operations,<br />

such as addition, subtraction, multiplication and division. Division by zero for the divide<br />

and modulo operations is checked by the internal object divisionCheck. This object is an<br />

in<strong>st</strong>ance of class DivisionACT which we encounter later when we describe dereification.<br />

EXAMPLE 10-1 A class NumericProcessor interface<br />

internals divisionCheck : DivisionACT;<br />

methods<br />

add(n1, n2 : Number) returns Number;<br />

subtract(n1, n2 : Number) returns Number;<br />

multiply(n1, n2 : Number) returns Number;<br />

divide(n1, n2 : Number) returns Number;<br />

modulo(n1, n2 : Number) returns Number;<br />

inputfilters<br />

divcheck : Meta = { [divide]divisionCheck.divBy0,<br />

[modulo]divisionCheck.divBy0 };<br />

calculate : Dispatch = { inner.* };<br />

end; // NumericProcessor interface<br />

class NumericProcessor implementation<br />

methods<br />

add(n1, n2 : Number) begin return n1 + n2 end;<br />

subtract(n1, n2 : Number) begin return n1 - n2 end;<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

ActiveMessage<br />

reification dereification<br />

meta filter ACT<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message<br />

• continue<br />

• reply<br />

• send<br />

77


78<br />

multiply(n1, n2 : Number) begin return n1 * n2 end;<br />

divide(n1, n2 : Number) begin return n1 / n2 end;<br />

modulo(n1, n2 : Number) begin return n1 mod n2 end;<br />

end; // NumericProcessor implementation<br />

The filter initializer of the meta filter divcheck has two filterelements which specify that<br />

only message with the selector divide and modulo is accepted and, consequently, reified.<br />

The sub<strong>st</strong>itutionpart of both elements define that, as a result, the message divBy0 is sent to<br />

the internal divisionCheck.<br />

EXAMPLE 10-1 B main<br />

temps<br />

aNumProc : NumericProcessor;<br />

result : Number;<br />

begin<br />

result := aNumProc.divide(3.0,2.0);<br />

result := aNumProc.divide(4.0,0.0);<br />

result := aNumProc.add(5.0, 6.0);<br />

end<br />

Figure 10-4 shows what happens upon the reification of the fir<strong>st</strong> divide message of the<br />

main method of example 10-1 B. The message which has 3.0 and 2.0 as arguments, is sent<br />

to the object aNumProc, an in<strong>st</strong>ance of class NumericProcessor. This active message is<br />

shown as aNumProc.divide( 3.0 , 2.0 ) in the diagram below.<br />

FIGURE 10-4 Reification of a message<br />

aNumProc.divide( 3.0 , 2.0 )<br />

NumericProcessor::divide(n1,n2)<br />

1.5<br />

Fir<strong>st</strong>, the message is filtered by aNumProc’s input filter divcheck. This meta filter accepts it<br />

and converts it to the reified message object aNumProc.divide( 3.0 , 2.0 ) , an in<strong>st</strong>ance of class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message. This message object is the single argument of the message<br />

divisionCheck.divBy0( ) , which is executed in a newly created thread. The original thread<br />

is blocked until the reified message is dereified. The divisionCheck.divBy0( ) message is<br />

sent to the divisionCheck object and is filtered by its input filters as normal. As a result,<br />

DivisionACT’s method divBy0 is invoked which dereifies its argument msg, the message<br />

object aNumProc.divide( 3.0 , 2.0 ) . It turns into the active message aNumProc.divide( 3.0 , 2.0 )<br />

again which then continues in NumericProcessor’s next filter, the dispatch filter calculate.<br />

This filter likewise accepts the message and after that, NumericProcessor’s method divide<br />

is invoked. This method eventually returns the Float object 1.5 as result of the message.<br />

10.4.2 Message dereification<br />

Reactivating a reified message —an in<strong>st</strong>ance of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message— is accomplished by<br />

sending an appropriate dereification message to it. There are three of such dereification<br />

messages which are all defined by the class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message (see also section 10.5):<br />

• continue, which causes the reified message to be reactivated: it continues its normal<br />

course, that is, it is filtered by the filters following the reifying meta filter and<br />

eventually invoke a method which returns a value;<br />

Chapter 10: Message passing semantics<br />

divcheck<br />

calculate<br />

return n1/n2<br />

aNumProc.divide( 3.0 , 2.0 )<br />

divisionCheck.divBy0( )<br />

DivisionACT::divBy0(msg )<br />

check


• reply(aReplyObject), which causes the message to become active again, and then<br />

provides aReplyObject as the return value of the message, ju<strong>st</strong> as if a method had been<br />

invoked that returned aReplyObject. In this case, the active message is not filtered by<br />

the filters following the reifying meta filter and no method is invoked;<br />

• send, which causes the message to be reactivated, like the continue message, except if<br />

the message has received a return value5 , the active message becomes reified again.<br />

Unlike continue, the dereification message send makes it possible to access the return<br />

value of the active message.<br />

After a send, the reified message mu<strong>st</strong> be reactivated again, either with a reply which<br />

can supply a different return value for the message, or with continue which does not<br />

change the return value of the message.<br />

EXAMPLE 10-1 C class DivisionACT interface<br />

comment<br />

’This class is an ACT that checks division operations of an in<strong>st</strong>ance<br />

of class NumericProcessor’;<br />

methods<br />

divBy0(msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message) returns nil;<br />

inputfilters<br />

check : Dispatch = { inner.* };<br />

end; // DivisionACT interface<br />

Dereification with<br />

continue<br />

class DivisionACT implementation<br />

methods<br />

divBy0(msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message)<br />

temps NAN : Number basicNew;<br />

begin<br />

if msg.numArgs = 2<br />

then<br />

if msg.argsAt(2) = 0<br />

then msg.reply(NAN); return<br />

end<br />

end;<br />

msg.continue; return<br />

end;<br />

end; // DivisionACT implementation<br />

We continue with the NumericProcessor example to show the use of these dereification<br />

messages. Division by zero for its divide and modulo operations was checked by an<br />

in<strong>st</strong>ance of class DivisionACT (example 10-1 C). This class is provides the divBy0 method<br />

which is invoked after a divide or modulo message has been reified by NumericProcessor’s<br />

divcheck meta filter. This reified message is then passed as the argument msg to the divBy0<br />

method. Note that in the divBy0 method the pseudo variable message refers to the message<br />

divisionCheck.divBy0( ) sent by the meta filter, whereas the argument msg refers to the<br />

reified message.<br />

Now, let us follow the message aNumProc.divide( 3.0 , 2.0 ) from example 10-1 B inside the<br />

class DivisionACT. It has been reified to aNumProc.divide( 3.0 , 2.0 )<br />

and now is the argument<br />

msg of the divBy0 method. This method checks if msg has two arguments and, if so,<br />

whether its second argument is zero. In this case, the second argument is 2.0 and therefore<br />

the divBy0 method dereifies the message by sending the continue message to it. As we can<br />

see in figure 10-5, it continues in the dispatch filter and invokes the divide method which<br />

calculates the result. After the divBy0 method has dereified the message, it executes the<br />

return <strong>st</strong>atement. This ends the method and also the thread in the DivisionACT. However,<br />

the method could have done more operations between the message dereification and the<br />

5. The return value is normally supplied if a method has been invoked which then returns some object, but it<br />

could also have been provided by another reification followed by a dereifying reply message.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

79


80<br />

end of the method. Those actions would have been carried out concurrently with the<br />

dereified message.<br />

FIGURE 10-5 Dereification of a message with continue<br />

Dereification with<br />

reply<br />

aNumProc.divide( 3.0 , 2.0 )<br />

NumericProcessor::divide(n1,n2)<br />

The divBy0 method also uses the message reply to dereify a message. If the second<br />

argument of the reified message is zero, DivisionACT has detected division by zero and will<br />

supply the Number object NAN —Not A Number— as reply of the message, in<strong>st</strong>ead of<br />

having the result calculated by NumericProcessor’s divide or modulo operation. The<br />

following figure shows the route of the second divide message of example 10-1 which has<br />

4.0 and 0.0 as arguments. Like the fir<strong>st</strong> message, the aNumProc.divide( 4.0 , 0.0 ) message is<br />

reified by the divisioncheck meta filter and becomes the argument msg of the divBy0<br />

method. Since the second argument of msg now is zero, the method supplies NAN as reply<br />

for the reified message aNumProc.divide( 4.0 , 0.0 ) . The execution of the now dereified<br />

message has finished because it has a received a return value: it has not been filtered by the<br />

NumericProcessor’s dispatch filter calculate and no method has been invoked.<br />

Subsequently, the add message (the third message of example 10-1 B) is executed. This<br />

message is not reified (it is rejected by the meta filter, since its selector is neither divide nor<br />

modulo), but invokes NumericProcessor’s add method at once.<br />

FIGURE 10-6 Dereification of a message with reply<br />

aNumProc.divide( 4.0 , 0.0 )<br />

NAN<br />

aNumProc.add( 5.0 , 6.0 )<br />

NumericProcessor::add(n1,n2)<br />

11.0<br />

1.5<br />

divcheck<br />

The third way of reactivating a reified message was by sending it a send message. We<br />

illu<strong>st</strong>rate this dereification message with the class LoggingProcessor which offers the same<br />

functionality as the NumericProcessor class from example 10-1, but additionally logs<br />

every message it receives. Example 10-2 A shows the interface and implementation of this<br />

class. The logging of messages is taken care of by the internal logger which is an in<strong>st</strong>ance<br />

of class LogACT. This class is able to <strong>st</strong>ore messages and also provides the functionality to<br />

display them is. The meta filter log reifies every message and then present it to logger. The<br />

internal np provides the behavior of class NumericProcessor. With the dispatch filter disp<br />

its behavior is inherited as well as the behavior of class LogACT. Note that the<br />

implementation of class LoggingProcessor is empty because this class does not define<br />

Chapter 10: Message passing semantics<br />

divcheck<br />

calculate<br />

divcheck<br />

calculate<br />

return n1/n2<br />

return n1+n2<br />

aNumProc.divide( 3.0 , 2.0 )<br />

divisionCheck.divBy0( )<br />

DivisionACT::divBy0(msg )<br />

aNumProc.divide( 4.0 , 0.0 )<br />

divisionCheck.divBy0( )<br />

DivisionACT::divBy0(msg )<br />

check<br />

check<br />

msg.continue<br />

msg.reply(NAN)


functionality itself but only composes behavior from the classes NumericProcessor and<br />

LogACT.<br />

EXAMPLE 10-2 A class LoggingProcessor interface<br />

internals<br />

np : NumericProcessor;<br />

logger : LogACT;<br />

inputfilters<br />

log : Meta = {[*.*]logger.log};<br />

disp : Dispatch = {np.*, logger.*};<br />

end; // LoggingProcessor interface<br />

class LoggingProcessor implementation<br />

end; // LoggingProcessor implementation<br />

Example 10-2 B presents the class LogACT. This class logs messages by <strong>st</strong>oring each<br />

reified message together with its return value in the in<strong>st</strong>ance variable loggedMessages.<br />

Every entry in this OrderedCollection is a two-element Array: the fir<strong>st</strong> element contains the<br />

message and the second element holds the return value of the message. The method<br />

showLog displays the logged messages. The log method <strong>st</strong>ores its argument msg (a reified<br />

message) in a new entry. It then dereifies this message with send and waits until send<br />

returns the return value of the message. This return object is <strong>st</strong>ored in the entry as well. At<br />

this point, the message again is reified and therefore has to be re<strong>st</strong>arted with continue in<br />

order to return the return object to the sender of the message. Finally, the log method adds<br />

the entry to the loggedMessages. Both methods have been made available at the interface<br />

by the dispatch filter disp.<br />

EXAMPLE 10-2 B class LogACT interface<br />

methods<br />

log(msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message) returns nil;<br />

showLog returns nil;<br />

inputfilters<br />

disp : Dispatch = {inner.*};<br />

end; // LogACT interface<br />

EXAMPLE 10-2 C main<br />

temps<br />

class LogACT implementation<br />

in<strong>st</strong>vars loggedMessages : OrderedCollection;<br />

methods<br />

log(msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message)<br />

temps entry : Array(2);<br />

begin<br />

entry.at:put:(1,msg);<br />

entry.at:put:(2,msg.send);<br />

msg.continue;<br />

loggedMessages.add:(entry)<br />

end;<br />

showLog<br />

temps i : SmallInteger; entry: Array(2);<br />

begin<br />

for i := 1 to loggedMessages.size<br />

begin<br />

entry := loggedMessages.at:(i);<br />

self.print(entry.at:(1));<br />

self.print(’ returned ’);<br />

self.printLine(entry.at:(2))<br />

end;<br />

end<br />

end; // LogACT implementation<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

81


82<br />

Dereification with<br />

send<br />

aLogProc : LoggingProcessor;<br />

result : Number;<br />

begin<br />

result := aLogProc.divide(3.0,2.0);<br />

result := aLogProc.divide(4.0,0.0);<br />

end<br />

We now illu<strong>st</strong>rate the dereification message send with example 10-2 C. The trace of the<br />

messages in this main method is shown in figure 10-7. The fir<strong>st</strong> message<br />

aLogProc.divide( 3.0 , 2.0 ) is reified by LoggingProcessor’s meta filter log. The logger object<br />

gets control over the presently reified message aLogProc.divide( 3.0 , 2.0 ) and dereifies it<br />

with send. The thread in the logger blocks until the message receives a return value. The<br />

message continues in LoggingProcessor’s disp filter which dispatches it to the<br />

NumericProcessor in<strong>st</strong>ance np. There, the meta filter divcheck reifies the message a second<br />

time and offers it to the DivisionACT in<strong>st</strong>ance. Since the second argument of the message is<br />

not zero, the divisionCheck object decides to dereify it with continue. The message then<br />

continues in np’s dispatch filter calculate. This invokes the divide method which returns the<br />

Float in<strong>st</strong>ance 1.5 as result of the message. Because the message aLogProc.divide( 3.0 , 2.0 )<br />

now has a return value, control is transferred back to the logger object which resumes its<br />

execution by returning the reply of that message, the object 1.5, as the result of the<br />

message send. The logger object <strong>st</strong>ores this reply object and then dereifies the message<br />

aLogProc.divide( 3.0 , 2.0 ) with continue. At this point, the message returns with the Float<br />

object 1.5 in main and has finished its execution.<br />

FIGURE 10-7 Dereification of a message with send<br />

aLogProc.divide( 3.0 , 2.0 )<br />

NumericProcessor::divide(n1,n2)<br />

1.5<br />

1.5<br />

aLogProc.divide( 4.0 , 0.0 )<br />

NAN<br />

NAN<br />

The second message of example 10-2 C, the message aLogProc.divide( 4.0 , 0.0 )<br />

, follows up<br />

to the divisionCheck object the same course as the previous. This object however,<br />

discovers a division by zero condition and supplies the NAN object as result for the<br />

message. Since the message now has a return value, further filtering is canceled and<br />

control is transferred back to the logger object. This object resumes its execution, <strong>st</strong>ores<br />

Chapter 10: Message passing semantics<br />

aLogProc.divide( 3.0 , 2.0)<br />

log<br />

logger.log( )<br />

disp<br />

LogACT::log(msg )<br />

disp<br />

divcheck<br />

calculate<br />

return n1/n2<br />

log<br />

disp<br />

divcheck<br />

logger.log( )<br />

LogACT::log(msg )<br />

msg.send<br />

divisionCheck.divBy0( )<br />

DivisionACT::divBy0(msg )<br />

1.5<br />

msg.continue<br />

disp<br />

msg.send<br />

divisionCheck.divBy0( )<br />

NAN<br />

aLogProc.divide( 4.0 , 0.0 )<br />

DivisionACT::divBy0(msg )<br />

msg.continue<br />

aLogProc.divide( 3.0 , 2.0 )<br />

check<br />

msg.continue<br />

aLogProc.divide( 4.0 , 0.0 )<br />

check<br />

msg.reply(NAN)


the reply object NAN and then dereifies the message aLogProc.divide( 4.0 , 0.0 )<br />

with<br />

continue. The messages subsequently finishes in main by returning NAN.<br />

10.4.3 Multiple reifications<br />

During the filtering of a message, the message can be reified several times if it is accepted<br />

by different meta filters. In the previous section we have already encountered this: the two<br />

messages of example 10-2 were reified by LoggingProcessor’s log filter and then by<br />

NumericProcessor’s divcheck filter.<br />

ACTs that dereified a message with continue or reply do not regain control over the<br />

message when it receives a reply. With the dereification message send however, the ACT<br />

gains control over the reified message and its reply value as soon as the message receives a<br />

reply. This reply is either a result of a method invocation or supplied by another ACT with<br />

the dereification message reply.<br />

It is possible that several ACTs are waiting for the reply on a message because they all<br />

dereified the message with send. When the message receives a reply, the ACTs will gain<br />

control over the message in the reverse order in which they were invoked by respective<br />

meta filters. As soon as the message receives a reply, the ACT which was invoked la<strong>st</strong> is<br />

the fir<strong>st</strong> to gain control over the message and its reply value. This ACT mu<strong>st</strong> dereify the<br />

message with continue or reply. Subsequently, the la<strong>st</strong> but one ACT gains control over the<br />

message and its reply. This ACT then dereifies the message, and so on, until fir<strong>st</strong> ACT<br />

dereifies the message.<br />

The following example shows the effect of this. The class DemonProcessor extends the<br />

behavior of class LoggingProcessor by altering the return value of a message. The class<br />

DemonACT is responsible for this modification. The change method adds one to the result<br />

of a message only if this result is a Number. Otherwise, the result of the message is not<br />

changed (example 10-3 A).<br />

EXAMPLE 10-3 A class DemonACT interface<br />

externals<br />

Number : Class;<br />

methods<br />

change(msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message) returns nil;<br />

inputfilters<br />

changeIt : Dispatch = {inner.*};<br />

end; // DemonACT interface<br />

class DemonACT implementation<br />

methods<br />

change(msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message)<br />

temps result : Any;<br />

begin<br />

result := msg.send;<br />

if result.class.inheritsFrom:(Number)<br />

then msg.reply(result+1)<br />

else msg.continue<br />

end<br />

end;<br />

end; // DemonACT implementation<br />

The class DemonProcessor composes the behavior of the class LoggingProcessor and the<br />

class DemonACT. A message sent to a DemonProcessor in<strong>st</strong>ance is logged with its correct<br />

result by the LoggingProcessor in<strong>st</strong>ance lp. If the result of the message is NAN, it is left<br />

unchanged, but if the result is a true number, the DemonACT in<strong>st</strong>ance demon adds one to it<br />

(example 10-3 B).<br />

EXAMPLE 10-3 B class DemonProcessor interface<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

83


84<br />

internals<br />

demon : DemonACT;<br />

lp : LoggingProcessor;<br />

inputfilters<br />

demon : Meta = {[*.*]demon.change};<br />

doit : Dispatch = {lp.*};<br />

end; // DemonACT interface<br />

class DemonProcessor implementation<br />

end; // DemonProcessor implementation<br />

EXAMPLE 10-3 C main<br />

temps<br />

aDemProc : DemonProcessor;<br />

result : Number;<br />

begin<br />

result := aDemProc.add(3.0,2.0)<br />

end; // main<br />

FIGURE 10-8 Multiple reifications<br />

aDemProc.add( 3.0 , 2.0 )<br />

NumericProcessor::add(n1,n2)<br />

5.0<br />

6.0<br />

Figure 10-8 shows the flow of the message of example 10-3 C. The message<br />

aDemProc.add( 3.0 , 2.0 )<br />

is accepted by DemonProcessor’s fir<strong>st</strong> filter, the meta filter demon.<br />

The message is reified and offered to the DemonACT in<strong>st</strong>ance demon. This object sends<br />

the message which continues through aDemProc’s dispatch filter doit. This filter<br />

dispatches it to the LoggingProcessor in<strong>st</strong>ance lp. The meta filter log of this object reifies<br />

the message a second time and offers it to the LogACT in<strong>st</strong>ance logger. The logger object<br />

dereifies the message with send causing it to continue in dispatch filter disp, the meta filter<br />

divcheck (which does not reify the message) and the dispatch filter calculate. Then,<br />

NumericProcessor’s add method is invoked which returns the Float object 5.0 as result of<br />

the message. Since the message now has a reply, the control is transferred back to the<br />

logger object which was the la<strong>st</strong> to send the message. The logger object logs the message<br />

and its return value 5.0 and reactivates the message with continue. The control will now be<br />

Chapter 10: Message passing semantics<br />

aDemProc.add( 3.0 , 2.0 )<br />

demon<br />

demon.change( )<br />

disp<br />

DemonACT::change(msg )<br />

doit<br />

log<br />

disp<br />

divcheck<br />

calculate<br />

return n1+n2<br />

msg.send<br />

5.0<br />

logger.log( )<br />

LogACT::log(msg )<br />

msg.reply(result+1)<br />

aDemProc.add( 3.0 , 2.0 )<br />

disp<br />

msg.send<br />

5.0<br />

msg.continue


transferred back to the demon object because it was the previous object which sent the<br />

message (with send). This object changes the reply of the message to 6.0. As there are no<br />

other ACTs which have sent (send) the message, this result for the message is eventually<br />

returned in main.<br />

If an ACT sends one of the dereification message continue, reply or send to a message<br />

which it already had dereified with continue or reply, this is semantically incorrect 6 . This is<br />

because the ACT gives up the control on the message after it has sent continue or reply to<br />

it. With the dereification message send, the ACT gains control on the message once it<br />

receives a reply. After a send, the message mu<strong>st</strong> be dereified once more with continue or<br />

reply. A send followed by a send however, is also incorrect. In the current version of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<br />

<strong>st</strong>, version 3.00, sending one of the dereification messages continue, reply or send after a<br />

continue or reply has no effect. Neither has sending a send after a send.<br />

10.4.4 Writing ACT methods<br />

In this section we give some hints and tips on writing methods which handle reified<br />

messages. We call a method which handles a reified message an ACT method. An ACT<br />

object can be an in<strong>st</strong>ance of any class which can, apart from one or more ACT methods,<br />

have other methods as well.<br />

• an ACT method mu<strong>st</strong> have one and only one argument, declared as an in<strong>st</strong>ance of class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message. This argument refers to the reified message;<br />

• the pseudo variable message in an ACT method refers to the message which was sent<br />

by the meta filter, while the argument of the method refers to the reified message;<br />

• it is important that message is dereified before ACT method finishes, because the<br />

message would otherwise remain reified forever. Thus, a message mu<strong>st</strong> be dereified<br />

with continue, reply or send, and after a send the message mu<strong>st</strong> be dereified a second<br />

time with continue or reply;<br />

• it is not necessary to do an early return in an ACT method, but<br />

• there is a possibility of deadlock if a message is dereified with send. If the thus<br />

dereified message does not return a value (for in<strong>st</strong>ance, through an infinite loop), the<br />

send in the ACT will wait on the return from the message forever. Further assume, that<br />

the ACT has protected its data with mutual exclusion by a wait filter (for in<strong>st</strong>ance, the<br />

defSync filter which is inserted by the compiler automatically). Since there is <strong>st</strong>ill a<br />

method active (viz. the ACT method), new messages to the ACT is blocked forever by<br />

the this wait filter.<br />

There is a solution for this. You can use an early return in the ACT method in order to<br />

‘free’ the ACT, but beware of protecting the data of the ACT that could be accessed<br />

after the early return. This could be solved by accessing the data of the ACT through<br />

self-calls.<br />

We could redesign the class from LogACT from example 10-2 B to prevent the deadlock<br />

situation from happening. The result has been presented in example 10-4. The log method<br />

now performs an early return and, after it has received the result of the reified message, it<br />

sends to itself the message logMessageAndReply. The corresponding method creates an<br />

entry for the message and its reply and <strong>st</strong>ores this.<br />

EXAMPLE 10-4 class LogACT interface<br />

methods<br />

log(msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message) returns nil;<br />

logMessageAndReply(msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message; result : Any) returns nil;<br />

showLog returns nil;<br />

inputfilters<br />

disp : Dispatch = {inner.*};<br />

6. To be more precise: it is semantically incorrect if in the same ACT thread, a message which was dereified<br />

with continue or reply, is dereified a second time.<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

85


86<br />

end; // LogACT interface<br />

class LogACT implementation<br />

in<strong>st</strong>vars loggedMessages : OrderedCollection;<br />

methods<br />

log(msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message)<br />

temps result : Any;<br />

begin<br />

return; // early return<br />

result := msg.send;<br />

msg.continue;<br />

self.logMessageAndReply(msg, result)<br />

end;<br />

logMessageAndReply(msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message; result : Any)<br />

begin<br />

temps entry : Array with:with:(msg,result);<br />

begin<br />

loggedMessages.add:(entry)<br />

end;<br />

showLog // ... as in example 10-2 B<br />

end; // LogACT implementation<br />

10.5 The class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message<br />

The class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message describes a reified message, i.e. a fir<strong>st</strong>-class representation of a<br />

message. As we have seen in section 10.4.1, a meta filter creates an in<strong>st</strong>ance of this class if<br />

it reifies an active message. This reified message is called a suspended message, because it<br />

represents a message of which the execution has been suspended. Dereifying a suspended<br />

message reactivates the message.<br />

We can also create an in<strong>st</strong>ance of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message by declaring a variable of this class,<br />

or by copying another reified message. The reified message created in this way has not<br />

been active before and we call such a message an idle message. Dereifying an idle<br />

message activates the message for the fir<strong>st</strong> time. This means that the message actually is<br />

sent: it is filtered and eventually invokes a method. During filtering, some meta filter could<br />

reify the message again and suspend its execution.<br />

The attributes of a reified message are the same as those of an active message<br />

(section 10.2). They include its selector, arguments, sender, server and receiver. The<br />

attributes of an active message can only be retrieved, but if the message is reified, they can<br />

be modified too. The class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message (appendix A.3, page 149) provides, in addition to<br />

the attributes accessing methods of class ActiveMessage (appendix A.2, page 148), also<br />

methods for changing, dereification and copying. They have been li<strong>st</strong>ed in the following<br />

table.<br />

TABLE 10-2 Accessing the reified message aMsg.<br />

aMsg.selector Returns a the selector of aMsg.<br />

aMsg.numArgs Returns the number of arguments of aMsg.<br />

aMsg.args Returns an Array containing the arguments.<br />

aMsg.argsAt(n) Returns the nth argument.<br />

aMsg.sender Returns the sender of aMsg.<br />

aMsg.server Returns the server of aMsg.<br />

aMsg.receiver Returns the receiver of aMsg.<br />

aMsg.setSelector(newSelector) Replace the selector by the String newSelector.<br />

Returns nil.<br />

aMsg.setArgs(argArray) Replace the argument by the Array object argArray.<br />

Returns nil.<br />

Chapter 10: Message passing semantics


TABLE 10-2 Accessing the reified message aMsg.<br />

aMsg.argsAtPut(n, newArg) Replace the nth argument by the object newArg.<br />

Returns nil.<br />

aMsg.setSender(newObj) Replace the sender by the object newObject. Returns<br />

nil.<br />

aMsg.setServer(newObj) Replace the server by the object newObject. Returns<br />

nil.<br />

aMsg.setReceiver(newObj) Replace the receiver by the object newObject. Returns<br />

nil.<br />

aMsg.copy Returns a copy of aMsg which has the same selector,<br />

server, receiver and arguments, but its sender is<br />

undefined (nil).<br />

aMsg.continue Dereify aMsg: it is activated for the fir<strong>st</strong> time if aMsg<br />

is an idle message, or reactivated if it is a suspended<br />

message. Returns nil.<br />

aMsg.fire Same as aMsg.continue: it (re)activates aMsg.<br />

aMsg.reply(anObject) Dereify aMsg and supply anObj as return value for the<br />

message. Returns nil.<br />

aMsg.send Dereify aMsg and wait until the message receives a<br />

reply. Returns this reply object.<br />

aMsg.sendContinue Same as aMsg.send; aMsg.continue<br />

If we send the dereification message send to a reified message, send will wait until the<br />

message receives a reply. The two other dereification messages continue and reply do not<br />

wait for a reply on the message. In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> version 3.00 however, dereification of an idle<br />

message with continue does wait for the reply.<br />

Copying a reified message creates an new in<strong>st</strong>ance of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message which has the<br />

same selector, arguments, server and receiver as its origin, but its sender is undefined (nil).<br />

This in<strong>st</strong>ance is an idle message which can be made active by sending one of the<br />

dereification messages to it.<br />

A variable which has been declared as an in<strong>st</strong>ance of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message has all its<br />

attributes undefined (nil). Before dereifying —actually sending— this idle message, at<br />

lea<strong>st</strong> the selector, the arguments and its server mu<strong>st</strong> be assigned. The following example<br />

shows the usage of a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message variable to create and send a message equivalent to<br />

3.0.divide(2.0).<br />

EXAMPLE 10-5 main<br />

temps<br />

msg : <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message;<br />

args : Array(1);<br />

result : Number;<br />

begin<br />

// The following <strong>st</strong>atements give the same answer as<br />

// result := 3.0.divide(2.0);<br />

msg.setSelector(’divide’);<br />

msg.setServer(3.0);<br />

args.at:put:(1,2.0);<br />

msg.setArgs(args);<br />

result := msg.send;<br />

end<br />

The Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

87


88<br />

Chapter 10: Message passing semantics


PART<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong><br />

iii Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

language<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language


11 Implementation<br />

Approach<br />

The previous part of this thesis, “Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language ”, described the syntax<br />

and semantics of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language. In this part we describe the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation<br />

which includes a programming environment consi<strong>st</strong>ing of a user interface, a compiler and<br />

a kernel. As <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> incorporates the composition filters object model, the implementation<br />

can be used to demon<strong>st</strong>rate the advantages of this model over the conventional objectoriented<br />

model. The <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation further can be used to verify several projects<br />

which use the composition filters object model to describe their design ([Tekinerdogan94],<br />

[Algra94], [Vuij<strong>st</strong>94], and [Marcelloni95]).<br />

The object-oriented language Smalltalk [Goldberg83], and the Objectworks\Smalltalk<br />

development environment [ParcPlace92] have been used to implement the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

language. This decision was made because Smalltalk allows rapid prototype development,<br />

it has a user friendly programming environment, and it comes with an extensive class<br />

library. Smalltalk further offers computational reflection [Maes87] [Ferber89] which<br />

means that it is possible to access the <strong>st</strong>ructure of each object (especially its methods) and<br />

the way it handles messages. For the implementation this is very useful, for in<strong>st</strong>ance to<br />

invoke a certain method directly. Finally, Smalltalk provides us with the basic entities<br />

(processes, semaphores, etc.) to implement concurrency and synchronization.<br />

This chapter describes the outline of the implementation. Section 11.1 identifies the<br />

implementation problems, while section 11.2 describes the implementation approach. The<br />

la<strong>st</strong> section gives an overview of the implementation.<br />

11.1 Problem <strong>st</strong>atement<br />

In the previous part of this thesis (part II, “Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language ”), we have<br />

described the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language, its syntax, and semantics. <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> has many features<br />

common to other object-oriented languages. It provides classes and objects, encapsulation,<br />

and inheritance and delegation. Polymorphic message passing is the basic mechanism to<br />

express executions in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> .<br />

However, there are major differences with programming languages which adopt the<br />

conventional object-oriented model. The composition filters object model incorporated by<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> offers some advantageous features which require a different approach to its<br />

implementation. The source of these differences lies in the message passing semantics of<br />

the composition filters object model.<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

91


92<br />

Message passing in the composition filters object model, as many object-oriented<br />

languages, follows the reque<strong>st</strong>/reply model: after a client object has sent a message —the<br />

reque<strong>st</strong>— to a server object, the client mu<strong>st</strong> wait until it receives a return value —the<br />

reply— from the server object. The message is a reque<strong>st</strong> from the client to carry out one of<br />

the operations provided by the server. The server decides whether it can execute the<br />

reque<strong>st</strong>, and which operation (method) corresponds to the message. Alternatively, the<br />

server can delegate the reque<strong>st</strong> to another object. This decision process is generally known<br />

as method lookup. If an appropriate method has been found, it is invoked and its result<br />

returned to the client object.<br />

In class based object-oriented languages, such as Smalltalk and C++ [Ellis90], the method<br />

lookup process considers the inheritance hierarchy to search for a method corresponding to<br />

the received message. Fir<strong>st</strong>, the it checks if the class of the server object has defined such a<br />

method. If this is not the case, its superclass will be consulted, etcetera, until an<br />

appropriate method has been found. Similarly, the delegation <strong>st</strong>ructure is searched for a<br />

matching method in delegation based languages, such as SELF [Ungar87].<br />

Filters In the composition filters object model adopted by <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> , the method lookup process is<br />

carried out by filters. If a client object sends a message to a server object, it will be filtered<br />

by several filters before eventually a method is invoked. A filter can delay a message (wait<br />

filter), abort a message (error filter), reify and then offer a message to a designated object<br />

(meta filter), or offer the message to another object for further filtering or method<br />

invocation (dispatch filter). Based on the message (typically its selector), and on<br />

conditions specified in the filter, the filter either carries out its predefined action on the<br />

message, or offers it to the next filter. Conditions provide information on the context of the<br />

message (typically its sender), and <strong>st</strong>ate of its receiver. By using filters, the concepts of<br />

inheritance, delegation, synchronization, and reflection on message communication can be<br />

realized.<br />

Reflection on messages There are two aspects of this filtering process which make the message passing semantics<br />

different from that of conventional object-oriented languages. Fir<strong>st</strong>ly, during the filtering<br />

of a message, several objects mu<strong>st</strong> reflect on the message. This means that they manipulate<br />

the message and access its attributes (selector, arguments, etc.). At sy<strong>st</strong>em level, a filter<br />

and its associated conditions access the attributes of a message in order to decide to accept<br />

or reject it. On application level, arbitrary objects (ab<strong>st</strong>ract communication types) may<br />

manipulate a reified message by changing its attributes or dereifying it.<br />

Dynamic filtering<br />

process<br />

Secondly, the filtering process is of a very dynamic nature, as conditions, reflecting the<br />

context of the message and <strong>st</strong>ate of its receiver, are used by filters to decide whether to<br />

accept or reject a message. The context of the message can differ from message to<br />

message, while the <strong>st</strong>ate of an object can change from one moment to another. This makes<br />

it possible that a message which is accepted at one moment by a filter, is rejected by it at<br />

another moment, or vice versa. With this dynamicity, the composition filters object model<br />

realizes dynamic inheritance and delegation (dispatch filter), synchronization (wait filter),<br />

and multiple views (error filter), which are concepts of dynamic nature.<br />

The implementation of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> mu<strong>st</strong> take these two aspects into account. Further, the<br />

implementation also mu<strong>st</strong> consider two other important features of the composition filters<br />

object model, concurrency and synchronization.<br />

Concurrency In the composition filters object model, several activities can be executed concurrently. In<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> these activities are called threads, which are in fact sequences of message sends. A<br />

new thread is created upon the invocation of an early return method, or when a message is<br />

reified by a meta filter and offered to an ACT object (see chapter 10). The implementation<br />

mu<strong>st</strong> realize these concurrent threads.<br />

Synchronization Wait filters can be used by a composition filters object to synchronize concurrent threads.<br />

A wait filter delays a message until designated conditions have been met. This means that<br />

the thread of the message is blocked, and that the conditions mu<strong>st</strong> be monitored to see if<br />

Chapter 11: Implementation Approach


<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language<br />

elements<br />

Programming<br />

environment<br />

the message is allowed to continue. The implementation mu<strong>st</strong> realize this by using lower<br />

level con<strong>st</strong>ructs available in the implementation environment.<br />

The “Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language ” (part II) shows that the primary language elements<br />

of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> are classes, objects, messages, filters, conditions, methods, and messages. A<br />

class ab<strong>st</strong>racts and groups objects according to their common behavior. An object<br />

encapsulates other objects (internals and in<strong>st</strong>ance variables), and provides methods which<br />

can be carried out in response to messages. The filters of an object, together with<br />

conditions, determine how it responds to messages. The implementation mu<strong>st</strong> realize these<br />

elements and preserve the semantics among them.<br />

For the automatic translation of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> to Smalltalk, the implementation mu<strong>st</strong> provide a<br />

compiler which compiles <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> source code to executable code. The compiler is part of<br />

the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> programming environment which is further comprised of a user interface, and a<br />

kernel. The user interface allows us to edit, compile and execute <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> applications. The<br />

kernel provides run-time support, and a set of predefined classes. The extensive class<br />

library of Smalltalk can be used in a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> application.<br />

As we have chosen Smalltalk as the implementation language and environment, we mu<strong>st</strong><br />

map the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> semantics and language elements onto Smalltalk. Smalltalk provides the<br />

basic means to accomplish this: it is an object-oriented language with classes, objects and<br />

methods, offers computational reflection 1 , and comes with the classes to realize<br />

synchronization and concurrency. Due to Smalltalk’s different message passing semantics,<br />

implementing <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> is not less trivial however.<br />

Summarizing, the implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language mu<strong>st</strong> address the following<br />

aspects:<br />

• mapping of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language elements and semantics on Smalltalk;<br />

• representation of filters and the filtering process;<br />

• reflection on messages;<br />

• dynamic nature of the filtering process;<br />

• concurrency with threads;<br />

• synchronization with the wait filter;<br />

• programming environment, including a compiler, user interface and run-time kernel.<br />

11.2 Approach<br />

In the following chapters of this thesis we describe how the implementation of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> can<br />

be realized. Fir<strong>st</strong>, we define the execution model which describes run-time aspects of<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> . It addresses the message passing semantics, and concurrency and synchronization.<br />

The design includes the representation of messages, the filtering process, the<br />

representation of filters, how methods are invoked, and message reification and<br />

dereification. The execution model is described in the following chapter.<br />

Chapter 13 defines the translation model. This describes the mapping of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language<br />

elements to Smalltalk entities. Basically it shows how a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> object with externals,<br />

internals, in<strong>st</strong>ance variables, filters, conditions, and methods, is represented in Smalltalk.<br />

This <strong>st</strong>atic model is used by the compiler for the automatic translation of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> source<br />

code in executable Smalltalk code.<br />

Finally, chapter 14 details the programming environment. It describes the compiler, which<br />

uses the translation model of the previous chapter, the user interface, and the kernel.<br />

1. As described in the introduction of this chapter, this means that it is possible to access the <strong>st</strong>ructure of each<br />

object and the way it handles messages.<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

93


94<br />

Graphical notation in<br />

forthcoming chapters<br />

Although performance and memory space are important for the practical use of<br />

programming languages, in this thesis we do not focus on efficiency but on ways how to<br />

implement one another. That does not mean we forget it completely: we will address the<br />

efficiency of some elements in the implementation, and, where possible, give hints on how<br />

to improve it.<br />

In the forthcoming chapters, we use a notation similar to OMT [Rumbaugh91] to denote<br />

<strong>st</strong>ructural relations in object diagrams. Figure 11-1 explains the elements that can be<br />

encountered in such diagrams.<br />

FIGURE 11-1 Legend for object diagrams<br />

Class<br />

Name<br />

Library Class<br />

Multiplicity of associations<br />

exactly one<br />

optional (zero or one)<br />

one or more<br />

11.3 Overview of the implementation<br />

The implementation provides a compiler which translates a user defined <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> object (a<br />

composition filters object) to a Smalltalk object (figure 11-2). The compiler employs the<br />

excution model and the translation model that are described in the following chapters. The<br />

translated Smalltalk object inherits from the class Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object which<br />

provides common behavior for all compiled <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> objects. The translated Smalltalk<br />

object is further composed of objects representing its filters, object manager, methods, etc.<br />

These objects are also provided as kernel classes.<br />

FIGURE 11-2 Overview of the implementation<br />

Class with<br />

specified attributes<br />

and operations<br />

Name<br />

attributes<br />

operations<br />

¤ class operations<br />

Chapter 11: Implementation Approach<br />

n<br />

m-n<br />

kernel objects<br />

Compiler<br />

Inheritance Aggregation<br />

SuperClass<br />

SubClass<br />

many (zero or more)<br />

exactly n<br />

m to n<br />

Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

user defined<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> object<br />

Execution Translation<br />

translated<br />

Smalltalk<br />

object<br />

Model Model<br />

Whole<br />

Part


12 Execution Model<br />

This chapter describes the execution model for <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> . The execution model describes<br />

how different entities behave at execution time (run-time). Messages are the basic entities<br />

involved in the execution of a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> application. When an object (the sender) sends a<br />

message to some receiver object, the message is filtered by several filters and, in general,<br />

invokes a method. The method executes and returns a reply object to the sender. As<br />

described in chapter 10, during the filtering process, a message can be reified by a meta<br />

filter, or delayed (synchronized) by a wait filter.<br />

Figure 12-1 shows an interaction diagram of the message execution. Similar diagrams will<br />

be used in this chapter to describe the implementation. It displays the interaction between<br />

various (Smalltalk) objects involved in (<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> ) message execution. In such a diagram,<br />

time increases towards the bottom. The thick line on the left represents the message thread<br />

which only indicates if it is suspended (dashed line), or not (solid line). A horizontal solid<br />

arrow indicates a reque<strong>st</strong> (Smalltalk message send) from the originator to the de<strong>st</strong>ination<br />

object. The label of this arrow represents the reque<strong>st</strong> (method name). An open arrow<br />

denotes the return from the reque<strong>st</strong>. If appropriate, the label of this arrow shows the object<br />

returned.<br />

FIGURE 12-1 Interaction diagram of message sending and filtering, and method invocation<br />

message<br />

thread sender message filter<br />

receiver<br />

method<br />

sending<br />

We <strong>st</strong>art this chapter by giving an overview of message execution. Then, we describe the<br />

implementation by following a message from the moment its is sent (section 12.2), when it<br />

is filtered (section 12.3) by several filter handlers (section 12.4), to the moment of method<br />

invocation (section 12.5). Section 12.6 describes the reification and dereification of<br />

messages, while section 12.7 explains the synchronization of messages. Finally,<br />

section 12.8 details how Smalltalk objects can under<strong>st</strong>and <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> messages.<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

filtering<br />

reply object<br />

invocation<br />

95


96<br />

12.1 Overview of message execution<br />

During message execution, filters and conditions mu<strong>st</strong> reflect on active messages (sy<strong>st</strong>em<br />

level reflection), while ab<strong>st</strong>ract communication type objects mu<strong>st</strong> reflect on reified<br />

messages (application level reflection). Therefore, we mu<strong>st</strong> design an implementation<br />

which allows this.<br />

Message We cannot use the message passing semantics of Smalltalk, because it does not allow to<br />

reflect on messages easily. We therefore use a Smalltalk object to represent a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

message. The following section describes this.<br />

Object A <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> object can be mapped to a Smalltalk object. For client objects, this object is a<br />

black box whose only task is to respond to a received message and return a reply object.<br />

The receiver encapsulates its internal <strong>st</strong>ructure and how it handles the received message. A<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> object —a composition filters object— reacts to a received message by passing it<br />

through its input filters. The mapping of a composition filters object to a Smalltalk object<br />

takes the same black box approach, as is shown by figure 12-1.<br />

In order to respond to (<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> ) messages, the object needs only two entry points which are<br />

inputMessage: and signatureIncludes:. The third entry point<br />

outputMessage: is private to the object. The fir<strong>st</strong> is used by client objects to direct a<br />

message to, while the second is used to check whether the object supports a message<br />

(signature matching).<br />

FIGURE 12-2 Entry points of a composition filters object in Smalltalk<br />

message<br />

The entry point called outputMessage: is the gate to the output filters and is<br />

represented in the translated object by a corresponding method. It is only used by the<br />

object itself when it sends a message that has to pass the output filters. The entry point<br />

inputMessage: is the gate to the input filters and also corresponds to a method. Every<br />

filter in the input filter group or output filter group has an entry point called filter:<br />

which is used to filter a message. A message passing through a filter group is offered to<br />

each filter through this entry point. A filter (dispatch filter) may decide that the message<br />

mu<strong>st</strong> be offered to another object (internal or external), which means that it is presented to<br />

the inputMessage: entry point of that object. Alternatively, a method of the object is<br />

invoked if the message is dispatched to inner.<br />

Thread A thread is a sequence of actions (messages) which can execute concurrently with other<br />

threads. A thread is mapped to a Smalltalk Process. A new Process can be created by<br />

forking a Smalltalk block closure. This is a sequence of <strong>st</strong>atements between brackets [].<br />

A Smalltalk Process is a non-preemptive process, which means that it occupies<br />

Smalltalk’s (virtual) Processor until the process explicitly gives it up. Another process<br />

mu<strong>st</strong> wait until the running process is terminated, becomes suspended, or takes itself of the<br />

processor. Because in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> new threads (processes) are created often, we have designed<br />

a preemptive process scheduler which gives each process frequently a little amount of time<br />

to run on the Processor. The preemptive process scheduler is part of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> kernel and<br />

will be described in chapter 14.<br />

Chapter 12: Execution Model<br />

filter:<br />

inputMessage:<br />

signatureIncludes:<br />

outputMessage:


12.2 Representation of an active message<br />

An active message represents a message that is executing. This means that it is being<br />

filtered, or that it has invoked a method. The attributes of an active message include:<br />

• its selector: determines which operation is reque<strong>st</strong>ed;<br />

• its arguments: an array of zero or more objects;<br />

• its sender: the object that has sent the message;<br />

• its server: the object to which the message was sent by the sender, i.e. it is the fir<strong>st</strong><br />

receiver;<br />

• its receiver: the object that is currently the receiver of the message, i.e. which is<br />

currently filtering the message.<br />

FIGURE 12-3 Active message<br />

selector<br />

args<br />

MessageSend<br />

receiver<br />

Message<br />

If an object sends a message, it mu<strong>st</strong> be offered either to the output filters of this sender<br />

object, or to the input filters of the server object. This depends on whether the server object<br />

is encapsulated by the sender object, or not. In the fir<strong>st</strong> case, the message does not have to<br />

“cross the encapsulation boundary of the sender object”, and can be offered to the input<br />

filters of the server directly. These kind of messages are messages sent to a con<strong>st</strong>ant, to an<br />

internal or in<strong>st</strong>ance variable of an object, or to a local variable of a method. A message that<br />

is sent to an external of an object mu<strong>st</strong> fir<strong>st</strong> pass the output filters of the sender object 1 . The<br />

choice between those two cannot always be made at compile time. Consider for example<br />

the message expression<br />

x.foo.bar<br />

in which the message bar is sent to the result object of the message foo, which is sent to the<br />

object x. At compile time, it is known whether x is an external or not, and the choice to<br />

offer the message foo to input or output filters can be made. However, for the result of this<br />

message, a so called intermediate object, this is not known, and this decision for message<br />

bar mu<strong>st</strong> be deferred to run-time. However, in this version of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> , version 3.00, this is<br />

not implemented yet. Messages to intermediate objects will not pass the output filters of<br />

the sender, but go <strong>st</strong>raight to the input filters of the object.<br />

A decision which always can be made <strong>st</strong>atically is whether a message is recursive or not. A<br />

recursive message is defined as a message to self, server, or sender (chapter 10).<br />

Ideally, <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> message sending should be carried out by Smalltalk message sending.<br />

However, this is not possible, since the virtual machine of Smalltalk takes control of it<br />

once the message has been sent: it performs method lookup in the class hierarchy and<br />

invokes a corresponding method. Because filters (and later other objects) mu<strong>st</strong> be able to<br />

reflect on messages, we use a fir<strong>st</strong>-class representation of the message. Smalltalk already<br />

1. A send filter in the output filter group ensures that the message is filtered by output filters of all the<br />

encapsulating objects, <strong>st</strong>arting from filters of the sender to those of the object which encapsulates the target<br />

of the message. After this, the message is offered to the input filters of the target of the message.<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

ActiveMessage<br />

sender<br />

server<br />

replyBlock<br />

from:to:deliver:arg:*<br />

from:to:send:arg:*<br />

replyValue:<br />

isRecursive<br />

¤ from:to:deliver:arg:*<br />

¤ from:to:send:arg:*<br />

Recursive-<br />

ActiveMessage<br />

isRecursive<br />

97


98<br />

provides two classes, Message and MessageSend, to represent such a message 2 . They<br />

have selector, arguments and receiver as attributes. The class<br />

RecursiveActiveMessage, representing a recursive message, is made a subclass of<br />

class ActiveMessage which is a subclass of MessageSend (figure 12-3). The<br />

RecursiveActiveMessage differs from class ActiveMessage only by overriding<br />

the isRecursive method. In the class ActiveMessage it returns false, while in its<br />

subclass it returns true.<br />

FIGURE 12-4 Interaction diagram of message sending<br />

Sending an active<br />

message<br />

Figure 12-4 shows the interaction diagram of message sending. There is a difference<br />

between messages which have to pass the output filters of the sender fir<strong>st</strong>, and messages<br />

which are offered to the input filters of the server directly. For this, class<br />

ActiveMessage provides two sets of in<strong>st</strong>ance methods. In both groups, methods are<br />

available for different number of (<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> ) arguments: a separate method for active<br />

messages with zero to four arguments, and a common method for active messages with<br />

more than four arguments. Each of these methods returns the object which is the result of<br />

the active message. The group with the selectors from:to:deliver:arg:* offers the<br />

message directly to the input filters of the server ( 1 ), while the from:to:send:arg:*<br />

method group offers the message to the output filters of the sender object ( 5 ).<br />

The methods in the two groups are very similar. Let us consider the following<br />

ActiveMessage>>from:to:send:arg:arg: method as an example for the<br />

methods in both groups. It is the send method for an active message which has two<br />

arguments, and which mu<strong>st</strong> pass the output filters of the sender.<br />

EXAMPLE 12-1A ActiveMessage>>from: sendr to: target send: selec arg: arg1<br />

arg: arg2<br />

sender := sendr.<br />

server := target.<br />

receiver := target.<br />

selector := selec.<br />

args := Array with: sender with: server with: arg1<br />

with: arg2.<br />

replyBlock := [:value|^value].<br />

6<br />

sender outputMessage: self.<br />

^nil<br />

The pseudo variables<br />

sender, server and self<br />

message<br />

thread<br />

sender<br />

¤from:to:deliver:<br />

The sender of the message is the object that has received the message fir<strong>st</strong>. In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> this<br />

object is referred to by the pseudo variable server. The pseudo variable self refers to the<br />

2. In Smalltalk a message is represented by a fir<strong>st</strong>-class object whenever the method lookup fails. This message<br />

object is passed as an argument to the doesNotUnder<strong>st</strong>and: message which is sent subsequently to the<br />

original receiver of the message.<br />

Chapter 12: Execution Model<br />

1<br />

5<br />

ActiveMessage output filters server input filters<br />

from:to:deliver:<br />

reply 4 3<br />

¤from:to:send:<br />

from:to:send:<br />

6 outputMessage:<br />

filtering<br />

2<br />

inputMessage:<br />

replyValue:reply<br />

inputMessage:<br />

filtering<br />

invocation<br />

reply<br />

method


object that currently received the method. The pseudo variable self can be mapped to the<br />

Smalltalk’s pseudo variable self. The pseudo variable server is mapped to a variable<br />

called server which is passed to the invoked method (see below). The fir<strong>st</strong> argument of<br />

the method above therefore is always be server. The second argument of the method,<br />

the target of the message, is as it appears in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> source code: it can be an con<strong>st</strong>ant<br />

object, an external, internal, in<strong>st</strong>ance variable of an object, a local variable of a method, or<br />

the result of another active message.<br />

One thing to be noted the message send method of in example 12-1A is that the sender and<br />

server of the message are passed as arguments to this method, and <strong>st</strong>ored in the active<br />

message. The que<strong>st</strong>ion arises whether this is always needed, or that they could be retrieved<br />

from the context of the message. Ideally, the sender and server should only be <strong>st</strong>ored if<br />

they are needed, i.e. if they are referred to in a method, or accessed by an ACT object.<br />

However, this cannot be determined at compile-time, as for in<strong>st</strong>ance, a message might be<br />

reified and offered to an ACT object which accesses the sender of the message at one time,<br />

while an identical message bypasses the ACT at another time. Therefore, they are always<br />

captured. Since Smalltalk does not have a direct equivalent of sender and server, we<br />

retrieve them when they are known, at the moment of the message send. It would be<br />

possible to retrieve them by using Smalltalk’s pseudo variable thisContext. This<br />

variable refers to context of the currently activated (Smalltalk) method through which the<br />

<strong>st</strong>ack of activated methods can be accessed. However, this requires a complicated travel<br />

through the <strong>st</strong>ack of contexts, because the <strong>st</strong>ack not only consi<strong>st</strong>s of compiled <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

methods but also methods involved in the message filtering process.<br />

Another thing we can see in the message sending method of example 12-1A is that both the<br />

sender and the server are <strong>st</strong>ored two times: once in the respective attributes, and then again<br />

in the array of arguments. The latter we have chosen because both the server and the<br />

sender are passed as parameter to the corresponding method. To invoke the method, the<br />

sender, server, and <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> arguments are packed in one array and passed as the Smalltalk<br />

arguments to the method (see section 12.5). By creating an array containing all these<br />

objects at this moment in<strong>st</strong>ead of adding them upon method invocation to an array<br />

containing only the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> arguments, we avoid the copying and creation of a new array<br />

in<strong>st</strong>ance. By <strong>st</strong>oring the sender and server also in separate attributes, these can be accessed<br />

fa<strong>st</strong>er when they are retrieved. The methods that change the attributes (sender: and<br />

server:) will both update the attribute and the corresponding entry in the args array. If<br />

performance <strong>st</strong>udies would show that mo<strong>st</strong> applications do not access the sender or server<br />

attributes of an active message, the attributes sender and server could be omitted, and<br />

be <strong>st</strong>ored in the args array only.<br />

Returning a value The attribute replyBlock of an ActiveMessage is initialized in the message sending<br />

method with a block closure (the <strong>st</strong>atements between the brackets []). When this block is<br />

executed, it returns its argument (value) as result of the from:to:send:arg:*<br />

method. This effectively returns value as reply object of the active message. The block<br />

closure is executed by the ActiveMessage>>replyValue: method, which is called<br />

if there is a reply available for the message, such as when an invoked method returns an<br />

object (marked with 3 in figure 12-4), or a reply is supplied by an ACT. By using the<br />

block closure, we can bypass the returns of several (Smalltalk) methods which were<br />

invoked during the filtering process of the message. These invoked methods form a <strong>st</strong>ack<br />

of activated contexts3 . In<strong>st</strong>ead of breaking this <strong>st</strong>ack down one by one by returning from<br />

each of these invoked methods normally, it is broken down to the context of the<br />

from:to:send:arg:* method immediately when the replyBlock is executed<br />

(marked with 4<br />

in figure 12-4).<br />

The replyBlock attribute is further used by message reification/dereification, in which<br />

case it is replaced by another block closure which intercepts the reply of the message once<br />

it becomes available (see section 12.6). The replyBlock can be seen as a return address<br />

3. The context <strong>st</strong>ack holds the <strong>st</strong>ate of execution. The invocation of a method adds a new context to the top of<br />

the <strong>st</strong>ack, while one is removed when a method finishes.<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

99


100<br />

Offering an active<br />

message to the filters<br />

as it would appear in an activation record during the execution of imperative languages. A<br />

return address is the address where the execution continues when the procedure has<br />

finished. The returnBlock block closure is similar: the execution continues after the<br />

call of the from:to:send:arg:* method.<br />

After the replyBlock has been initialized, the message mu<strong>st</strong> be offered to the input or<br />

output filters (in figure 12-4 marked with 2 and 6<br />

). For this, a translated <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> object<br />

has two methods inputMessage: and outputMessage: which pass their argument,<br />

an ActiveMessage in<strong>st</strong>ance, to its input filters and output filters, respectively.<br />

The la<strong>st</strong> line of the method of example 12-1A (^nil) is placed as a safeguard. It should<br />

never be executed, however, because a return from an active message is implemented by<br />

the calling the replyValue: method which executes the replyBlock block closure.<br />

Selector of a message The selector of an active message is an in<strong>st</strong>ance of the Smalltalk class Symbol which is<br />

an efficient implementation of a <strong>st</strong>ring. The selector is a sequence of alphanumeric<br />

characters equivalent to its appearance in the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> source code. It is equivalent to the<br />

selectors which are used by the filters in the filtering process. It would have been<br />

convenient if we could have used the same selector as the Smalltalk selector of the method<br />

to be invoked eventually. Such a selector contains as much sub-keywords as there are<br />

arguments in the method (see for in<strong>st</strong>ance the selector of the method of example 12-1A).<br />

This would require the number of arguments to be known at compile-time which is not<br />

always the case. The chosen selector representation also allows easy comparison of the<br />

selector of the message during the filtering process, and simple replacement of a selector.<br />

Creating and sending an<br />

active message<br />

As we have argued in the beginning of this section, every message is represented by a fir<strong>st</strong>class<br />

object. This means that every message which appears in the source code mu<strong>st</strong> be<br />

created and then sent. Similar to the two groups of in<strong>st</strong>ance methods, the class<br />

ActiveMessage provides two groups of class methods, from:to:deliver:arg:*<br />

and from:to:send:arg:* that correspond to the aforementioned two groups of<br />

in<strong>st</strong>ance methods. These methods fir<strong>st</strong> create an ActiveMessage in<strong>st</strong>ance. They<br />

subsequently send it, by calling the corresponding in<strong>st</strong>ance method, and return the object<br />

replied by the message. Example 12-1 B shows the class method corresponding to<br />

example 12-1A.<br />

EXAMPLE 12-1 B ActiveMessage class>>from: sendr to: target send: selec arg:<br />

arg1 arg: arg2<br />

^self basicNew<br />

from: sendr<br />

to: target<br />

send: selec<br />

arg: arg1<br />

arg: arg2<br />

We will now give an example of how <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> messages are converted to Smalltalk.<br />

Consider the following message expression:<br />

EXAMPLE 12-2 A Tarzan.age.less(40); // Tarzan.age < 40<br />

The message age is sent to the object Tarzan. Then, the message less is sent to the object<br />

resulting from the fir<strong>st</strong> message. Assuming that Tarzan is an internal (meaning that the<br />

message then does not have to pass the output filters), this is translated to Smalltalk as:<br />

EXAMPLE 12-2 B ActiveMessage<br />

from: self<br />

to: (ActiveMessage<br />

from: self<br />

to: Tarzan<br />

Chapter 12: Execution Model


deliver: #age)<br />

deliver: #less<br />

arg: 40.<br />

As we see, the target of the less message is the result of the fir<strong>st</strong> message, the age<br />

message. The compiler correctly generates Smalltalk code for more complex situations,<br />

for in<strong>st</strong>ance if the arguments are also message expressions.<br />

12.3 Filtering a message<br />

The filtering of a message is carried out by individual filters, which are organized in<br />

groups of input filters and output filters. In this section we fir<strong>st</strong> describe the filtering of a<br />

message by a group of filters, and subsequently by each individual filter.<br />

12.3.1 Message handling by a filter group<br />

The filtering of a message in a group of filters is mutual exclusive, which means that if<br />

there is a message being filtered by the filter group, messages that want to enter the group<br />

to be filtered mu<strong>st</strong> wait until the currently evaluating message leaves the group. This<br />

ensures that not more than one message gets accepted when they access a condition.<br />

Messages mu<strong>st</strong> pass the filter group in the order in which they arrive.<br />

A message can leave the filter group for good, or only temporarily. The former is the case<br />

if the message is offered to another object (possibly inner) by a dispatch or send filter, or if<br />

the message is aborted by an error filter. The message can temporarily leave the group<br />

when its is delayed by a wait filter, or reified by a meta filter. Once the message is re<strong>st</strong>arted<br />

or dereified, it mu<strong>st</strong> continue through the re<strong>st</strong> of the filters by reentering the filter group.<br />

However, if at this moment another message already occupies the group, the message mu<strong>st</strong><br />

wait until the group is free. Because a reentering message was already evaluating in the<br />

filter group, it arrived before messages which are waiting to enter the filter group for the<br />

fir<strong>st</strong> time. To guarantee the ordering of the messages, these reentering messages have<br />

priority over those which want to enter group for the fir<strong>st</strong> time.<br />

This could be implemented by two queues Q1 and Q2 which <strong>st</strong>ore messages that want to<br />

enter the filter group for the fir<strong>st</strong> time, and messages that want to reenter the group,<br />

respectively. If a message that wants to enter a filter group for the fir<strong>st</strong> time finds that there<br />

is no message being filtered by the group, it can enter the group immediately. Otherwise it<br />

has to wait in Q1. If a message that wants to reenter the group (because the conditions in a<br />

wait filter were met, or it was dereified) finds the group unoccupied, it can enter<br />

immediately, otherwise it mu<strong>st</strong> wait in Q2.<br />

When a message leaves a group (either temporarily or definitely), it mu<strong>st</strong> trigger a<br />

following message to enter the group. It mu<strong>st</strong> fir<strong>st</strong> check if the queue Q2 contains<br />

messages, since these reentering message have priority over the messages of queue Q1.<br />

Since this would require the checking two queues, we have combined them into a single<br />

queue. The class MessageQueue implements a single message queue with a priority<br />

part. Messages are always taken from the head of the queue. In the priority part (at the<br />

front of the queue) messages are added that want to reenter the filter group. Messages that<br />

want to enter for the fir<strong>st</strong> time are added to the tail of the queue. If the priority part is<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

101


102<br />

empty, i.e. if there are no messages that want to reenter the filter group, messages are<br />

automatically taken from the second part of the queue.<br />

FIGURE 12-5 Messages entering a filter group<br />

priority part<br />

MessageQueue<br />

Figure 12-5 shows a MessageQueue (a) and an example of the working of it (b-h).<br />

Message 2 mu<strong>st</strong> wait in the message queue because message 1 is occupying the group (b).<br />

When message 1 has left the filter group, message 2 enters the filter group, while messages<br />

3 and 4, which arrived in the mean time, mu<strong>st</strong> wait (c). Then, because message 2 is<br />

blocked by the fir<strong>st</strong> filter, it temporarily leaves the group, and as a result message 3 enters<br />

the group (d). Message 3 continues in the next filter, and due to some other event, message<br />

2 is re<strong>st</strong>arted again, and mu<strong>st</strong> wait in priority part of the queue as it tries to renter the group<br />

(e). When message 3 leaves the input filter group (temporarily in this case), message 2<br />

enters the group and continues with the second filter (f). Then, message 2 is blocked for a<br />

second time, leaves the filter group, and triggers message 4 to enter it. After this, message<br />

3 is again re<strong>st</strong>arted and entered in the priority part of the queue (g). While message 4<br />

continues in the following filter, message 2 is re<strong>st</strong>arted again and entered in the priority<br />

part of the queue.<br />

Now let us have a closer look on how the input filter group and output filter group are<br />

represented in a compiled user defined object. As we have said earlier, every user defined<br />

object inherits from the class Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object which provides operations<br />

common to all translated <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> objects. We do not explicitly model the input or output<br />

filters group as a separate object, but since every user defined object has its own separate<br />

set of filters, they are represented as in<strong>st</strong>ance variables (part of) the user defined object (see<br />

figure 12-6).<br />

FIGURE 12-6 Object diagram of message filtering<br />

filter:<br />

Each of the two filter groups has a message queue to <strong>st</strong>ore messages hold messages as<br />

described above. Since they are always there, they are part of Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object.<br />

This class also provides methods to enter a group of filters for the fir<strong>st</strong> time<br />

Chapter 12: Execution Model<br />

4<br />

4<br />

2 3<br />

4 2<br />

1 2 3<br />

5<br />

4<br />

3 2<br />

filter group<br />

2<br />

3 2<br />

(a) (b) (c) (d) (e) (f) (g) (h)<br />

Filter<br />

Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

enterInput:<br />

enterInputAgain:<br />

leaveInput<br />

enterOutput:<br />

enterOuputAgain:<br />

leaveOutput<br />

UserDefinedObject<br />

inputMessage:<br />

outputMessage:<br />

filters→<br />

6<br />

5<br />

3<br />

4<br />

2<br />

MessageQueue<br />

ActiveMessage<br />

semaphore<br />

wait<br />

signal<br />

<strong>st</strong>ores↓<br />

6<br />

5<br />

2<br />

3<br />

4


(enterInput: and enterOutput:), to reenter the group (enterInputAgain:<br />

and enterOutputAgain:), or to leave the group (leaveInput and<br />

leaveOutput). The fir<strong>st</strong> four methods take an active message as an argument. They<br />

block the message as described above. The leaveInput and leaveOutput methods<br />

of Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object mu<strong>st</strong> trigger the next message to enter the filter group by<br />

signalling the fir<strong>st</strong> message, if any, in the input or output filters queue.<br />

To block an active message, the class ActiveMessage has a semaphore attribute<br />

which is an in<strong>st</strong>ance of class Semaphore. The two methods wait and signal block<br />

and re<strong>st</strong>art the message, respectively. A semaphore works like this: if it has not received a<br />

signal when it receives a wait, the thread (process) that sent this wait is suspended<br />

until a signal is received. Suspending the thread thus blocks the active message. Note<br />

that blocking an active message always happens within the active message thread itself,<br />

but its release is carried out by another thread. The semaphore of ActiveMessage, and<br />

associated methods are also used to block a message for synchronization by a wait filter,<br />

and during its reification by a meta filter.<br />

The user defined object has the methods inputMessage: and outputMessage:<br />

which are the ports to the input and output filter group. They are called when an active<br />

message mu<strong>st</strong> be filtered by the input filters or output filters of the object. Their task is to<br />

pass the argument message through each filter in the group. Every user defined object has<br />

its own specific set of filters which are appear as in<strong>st</strong>ance variables of the user defined<br />

object. Because these methods depend on these filters, they are generated by the compiler.<br />

EXAMPLE 12-3 UserDefinedObject>>inputMessage: anActiveMessage<br />

self enterInput: anActiveMessage.<br />

(inputf1 filter: anActiveMessage) ifFalse: [<br />

(inputf2 filter: anActiveMessage) ifFalse: [<br />

(inputf3 filter: anActiveMessage) ifFalse: [<br />

... ifFalse: [<br />

self leaveInput.<br />

Filter inputFiltersErrorSignal raise] ...]]]<br />

The general <strong>st</strong>ructure of the inputMessage: method is shown in example 12-3, with<br />

the outputMessage: method being very similar to that. The message mutual<br />

exclusively enters the input filters group with the enterInput: method. Then, the<br />

message is offered to each of the input filters in turn by calling the filter: method of<br />

the respective filters. As we will see in the next section, this method returns false if the<br />

message mu<strong>st</strong> be processed by the following filter. The message has left the filter group<br />

definitely if the filter: method returns true. In this case, the filter has called the<br />

leaveInput method to free the filter group 4 . If the message has passed all the filters<br />

without being “filtered out”, a corresponding error is raised, after it has freed the group. If<br />

a message leaves the group temporarily, the corresponding filter (a meta or wait filter)<br />

frees the group by calling the leaveInput method. The filter subsequently blocks the<br />

message and processes it for its own purposes. After the message is released, the message<br />

reenters the group by calling the enterInputAgain: method. This places the message<br />

in the priority part of the input filters queue.<br />

12.3.2 Message handling by a filter<br />

Now the message arrives at the level of an individual filter. When a filter filters a message,<br />

the filter has to decide whether to accept or to reject the message. If the message is<br />

accepted by the filter, the accept action of the filter mu<strong>st</strong> be carried out. In the opposite<br />

case, if the message is rejected, the reject action of the filter mu<strong>st</strong> be carried out. The<br />

decision whether to accept or reject a message is called the accept te<strong>st</strong> and has been<br />

described in chapter 9. The accept te<strong>st</strong> is common to each filter handler, while the accept<br />

4. The filter has an in<strong>st</strong>ance variable, called object, so that it knows of which object it is a filter of, and where<br />

to send the leaveInput message to.<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

103


104<br />

and reject actions differ for each type of filter handler. In this section we focus on the<br />

accept te<strong>st</strong>, while the next section describes the specific actions of the various filter<br />

handlers.<br />

The accept te<strong>st</strong> The accept te<strong>st</strong> decides if a filter has to accept or to reject a message. The filter initializer<br />

of a filter (the part between the curly braces in the filter declaration) defines which<br />

messages it accepts. Other messages are rejected. In the definition of the accept te<strong>st</strong><br />

(section 9.4, page 66), the message is checked again<strong>st</strong> every filter element in the filter<br />

initializer from left to right, until one accepts it. For a filter element to accept a message:<br />

• the condition mu<strong>st</strong> evaluate to true (condition evaluation);<br />

• the selector of the message mu<strong>st</strong> match with one specified in the filter element (selector<br />

matching);<br />

• either, the target of the message mu<strong>st</strong> match with the target of the matching part μ, for<br />

a message pattern [μ]σ that consi<strong>st</strong>s both of a matching part μ and a sub<strong>st</strong>itution part σ,<br />

and that is not the pattern of an exclusion element (receiver matching);<br />

• or, the message mu<strong>st</strong> be included in the signature of the target of σ, for a message<br />

pattern σ that consi<strong>st</strong>s only of a sub<strong>st</strong>itution part, or a message pattern [μ]σ in an<br />

exclusion element —of which the matching part μ is ignored (signature matching).<br />

If the filter element accepts a message, a new target object and selector is returned. They<br />

are used by the filter as the target and selector of an ACT message (meta filter), or as<br />

replacement for those of the message (dispatch, send, and error filter) (yielding a<br />

sub<strong>st</strong>itution target and selector).<br />

It is clear that selector matching and receiver matching are the cheape<strong>st</strong> operations in the<br />

accept te<strong>st</strong>, as they require only the comparison of two selectors (<strong>st</strong>rings), or object<br />

pointers. Signature matching also requires the comparison of selectors, but is less cheap<br />

(see section 12.3.3). The mo<strong>st</strong> expensive operation is condition evaluation, which requires<br />

the invocation of a condition. To implement the accept te<strong>st</strong> efficiently, it should evaluate<br />

conditions only when necessary, that is, when the selector of the message matches the<br />

selector in the filter element. However, the filter initializer does not specify which<br />

conditions have to be evaluated for one particular message selector separately. This is<br />

because the same selector can appear in several filter elements. In order to see if a message<br />

that has been blocked by a wait filter can be unblocked, it would also be very convenient to<br />

reevaluate only those conditions that are relevant for the blocked message.<br />

FIGURE 12-7 Object diagram of Filters<br />

We propose to implement a filter as a selector dictionary, which specifies for every<br />

message selector which conditions and matchings mu<strong>st</strong> be evaluated in order to accept the<br />

message. This dictionary is a table of the conditions/matchings, indexed by the selector.<br />

Note that only the selectors explicitly mentioned in the filter initializer should have a<br />

separate entry, because conditions/matchings have been specified for them. Other<br />

Chapter 12: Execution Model<br />

Dictionary<br />

SelectorDictionary<br />

Filter<br />

filter:<br />

conditionValue:tarColl:selColl:<br />

BlockClosure


selectors, for which the same conditions/matchings mu<strong>st</strong> be evaluated, can be mapped to<br />

the same entry. The accept te<strong>st</strong> for a message consi<strong>st</strong>s of retrieving the conditions for the<br />

selector of the message, and evaluating them. The accept te<strong>st</strong> collects a new target and<br />

selector which are passed to the accept or reject action of the filter accordingly. For the<br />

conversion of a filter initializer to a selector-condition dictionary we have designed an<br />

algorithm which is described in appendix D. The algorithm extracts for each selector the<br />

conditions to be evaluated, the receiver or signature match to be performed, and the target<br />

or selector to be returned.<br />

Figure 12-7 shows the classes involved. A SelectorDictionary is a selector indexed<br />

hash table which has, in addition to its superclass Dictionary, a default entry that is<br />

returned if a selector entry is reque<strong>st</strong>ed for which a separate entry is not available. This is<br />

used to map the selectors not explicitly mentioned in the filter initializer. In the subclass<br />

Filter an entry for a selector is a code section —a block closure— which specifies all<br />

the conditions, receiver and signature matchings to be evaluated for a that specific selector,<br />

and additionally, the target and selector to yield. The class Filter is the superclass for<br />

each filter handler class. They will be described in the following section.<br />

Now let us have a closer look at an entry of a filter. Such an entry is a block closure<br />

containing a boolean expression which is composed of the conditions and matchings to be<br />

evaluated for a single selector. Since the boolean expression depends on the conditions and<br />

matching functions in the filter initializer, it is generated by the conversion algorithm in the<br />

compiler. The message to be te<strong>st</strong>ed is passed as a parameter to the block which returns a<br />

boolean indicating whether it mu<strong>st</strong> be accepted or not. Conditions receive this active<br />

message as a parameter when they are evaluated, thus making the pseudo variable<br />

message accessible inside conditions. The block closure also mu<strong>st</strong> yield a new target or<br />

selector when the message mu<strong>st</strong> be accepted. For this, the block has two additional<br />

parameters (block closures, again) which are used to set a new target or selector. To see<br />

how a typical block closure would look like, consider the following filter initializer.<br />

EXAMPLE 12-4 A { full=>super1.*, [retrieve]inner.get, empty=>inner.get };<br />

In this filter initializer, two selectors have been explicitly mentioned (retrieve, get), and the<br />

conversion algorithm accordingly generates three block closures (two for the explicit<br />

selectors, and a default for all other selectors). These are shown below.<br />

EXAMPLE 12-4 B #retrieve-><br />

[:msg :tarBlk :selBlk|<br />

((object full: msg) and: [super1 signatureIncludes: #retrieve])<br />

ifTrue: [tarBlk value: super1. true]<br />

ifFalse: [tarBlk value: inner. selBlk value: #get. true]<br />

]<br />

#get-><br />

[:msg :tarBlk :selBlk|<br />

((object full: msg) and: [super1 signatureIncludes: #get])<br />

ifTrue: [tarBlk value: super1. true]<br />

ifFalse: [<br />

(object empty: msg)<br />

ifTrue: [tarBlk value: inner. selBlk value: #get. true]<br />

ifFalse: [false]]<br />

]<br />

DEFAULT-><br />

[:msg :tarBlk :selBlk|<br />

((object full: msg) and: [super1 signatureIncludes: msg selector])<br />

ifTrue: [tarBlk value: super1. true]<br />

ifFalse: [false]<br />

]<br />

The class Filter provides the method conditionValue:tarColl:selColl: to<br />

evaluate the conditions/matchings for a message. It retrieves from itself the block closure<br />

corresponding to the selector of the message, evaluates it, and collects a new target and<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

105


106<br />

selector. The filter: method is now very simple (example 12-5). It collects a new<br />

target and selector while it evaluates the conditions, and then accordingly executes the<br />

accept or reject action. It returns true to indicate that the message has left the filter group<br />

definitely, and false if the message needs to be filtered by the following filter. For<br />

efficiency reasons the filter: method is overridden in the various filter handler<br />

subclasses. For each filter handler, its specific accept and reject actions are inlined in the<br />

ifTrue:ifFalse: <strong>st</strong>atement.<br />

EXAMPLE 12-5 Filter>>filter: anActiveMessage<br />

|newTarget newSelector|<br />

(self<br />

conditionValue: anActiveMessage<br />

tarColl: [:t | newTarget := t]<br />

selColl: [:s | newSelector := s])<br />

ifTrue: [^self<br />

accept: anActiveMessage<br />

target: newTarget<br />

selector: newSelector]<br />

ifFalse: [^self<br />

reject: anActiveMessage<br />

target: newTarget<br />

selector: newSelector]<br />

Discussion We can conclude that the major work of the filter accept te<strong>st</strong> is done by the conditions/<br />

matchings block closures. The number of condition blocks depends on the number of<br />

selectors explicitly mentioned in the filter initializer. In mo<strong>st</strong> filters this number does not<br />

exceed 5 to 7. When a filter filters a message, only a single condition block closure has to<br />

be evaluated. We have not timed the evaluation of a block closure, but as a block is similar<br />

to a method, this is comparable to method invocation time. We could try and compare this<br />

with an alternative implementation in which the code of each separate condition block is<br />

combined with a case <strong>st</strong>atement in the conditionValue:tarColl:selColl:<br />

method. This alternative has a disadvantage: the conditions on which a message blocks in<br />

a wait filter are no longer available separately.<br />

12.3.3 The signature of an object and signature matching<br />

The signature of an object defines the operations (i.e. messages) it supports. The signature<br />

of an object consi<strong>st</strong>s of its own operations (the interface methods) and the operations of the<br />

objects to which it delegates (the target objects in dispatch filters). The latter is defined<br />

(recursively) by the signatures of the respective target objects. Although conditions can<br />

affect to which object a message is delegated, and thus at some moment the owning object<br />

might support the operations of some target object, the signature includes all possible<br />

operations irrespective of the conditions. This may lead in choosing the false object to<br />

dispatch a message to, for which a solution is proposed below.<br />

Signature matching mu<strong>st</strong> check if an active message is included in the signature of a<br />

designated object. If this is the case, and provided that the conditions evaluated to true, the<br />

message can be accepted. In the case of a dispatch filter, this means that the message is<br />

dispatched to this object. Signature matching therefore is the key to inheritance and reuse<br />

in the composition filters object model.<br />

In this section we fir<strong>st</strong> ju<strong>st</strong>ify the definition of an signature of an object, and subsequently<br />

describe how signature matching is implemented.<br />

Signature of an object The definition 9-1 of the signature of an object (page 68) specifies a simple signature,<br />

because it only considers the selectors of methods. A full signature would also account for<br />

the number of method parameters, their types, and the type of the object returned by the<br />

method [Wirfs-Brock90]. Since we do not address type checking in this thesis, the given<br />

definition proves to be sufficient.<br />

Chapter 12: Execution Model


The signature of an object specifies the operations this object supports, and it basically<br />

includes the selectors of its interface methods, and, recursively, the operations supported<br />

by its internals and externals. However, not always all the externals and internals<br />

contribute to the signature. If an object does not use an internal/external to dispatch<br />

messages to (but uses it as an ACT in<strong>st</strong>ead), the object does not support its operations, and<br />

therefore this internal/external does not add to the signature of the object. Additionally, the<br />

signature of an object includes the selectors that are sub<strong>st</strong>ituted in a message by some<br />

input filter. To under<strong>st</strong>and this, consider a class which defines an interface method get and<br />

has the following two input filters<br />

EXAMPLE 12-6 A sub<strong>st</strong> : Error = { [retrieve]get, *};<br />

disp : Dispatch = { inner.get };<br />

It is obvious that this class also supports retrieve messages, as the error filter replaces the<br />

selector of such a message by get, upon which the get method is invoked. Therefore, the<br />

signature also includes the selectors that are sub<strong>st</strong>ituted the message by an input filter.<br />

Note that only an (input) error or dispatch filter do a sub<strong>st</strong>itution of the message selector,<br />

and that output filters do not contribute to the signature of an object.<br />

One thing we cannot detect, or only with great effort, is if an ACT affects the signature of<br />

an object. The definition of the signature of an object disregards this possibility. However,<br />

this may not always be correct, and has the consequence that an object is not chosen to<br />

dispatch a message to, although it supports the operation. For in<strong>st</strong>ance, the signature of the<br />

object of example 12-6 A does not include retrieve, but <strong>st</strong>ill supports retrieve messages if<br />

the sub<strong>st</strong>itution of the retrieve selector was carried out by an ACT in<strong>st</strong>ead of the error filter.<br />

That is, if the error filter had been replaced by the meta filter<br />

EXAMPLE 12-6 B sub<strong>st</strong> : Meta = { [*]anACT.modifyMessage };<br />

in which the modifyMessage method of anACT, apart from possible other things, replaces<br />

a retrieve selector by get. It requires semantic analysis of (the methods of) an ACT to<br />

detect this.<br />

Because the signature of an object is based on the operations it supports (directly or<br />

indirectly), irrespective of the conditions, this object can inadvertently be chosen as the<br />

target to dispatch a message to. This can happen if a message is in the signature of the<br />

object, but conditions prevent the message to be dispatched to inner, or to its internals or<br />

externals. If this object is chosen to dispatch the message, the message is likely to pass all<br />

the filters in the filter group and then causes an error exception.<br />

The similar situation can appear if a message is delayed by a wait or meta filter of an<br />

object. Suppose its conditions initially would allow a message to be executed, but during<br />

the delay they change in such a way that the message cannot be dispatched any more: the<br />

message is likely to cause an error exception. While the fir<strong>st</strong> is caused by the signature<br />

definition not being fine grained enough (i.e. it should consider the conditions), the latter is<br />

caused by the application because the <strong>st</strong>ate of the object changed. In the latter case the<br />

application should take precautions to prevent this, while the fir<strong>st</strong> mu<strong>st</strong> be solved by the<br />

implementation, by refining the definition of the signature of an object in order that it<br />

considers conditions as well.<br />

Signature matching The signature matching has been implemented in the following way. Every user defined<br />

object has a method called signatureIncludes: which takes the selector of the<br />

message to be checked as parameter. It fir<strong>st</strong> checks if it is supported by its private<br />

signature, that is, if the selector is the selector of an interface method, or a selector<br />

sub<strong>st</strong>ituted by an input filter. If not, the signatures of the objects to which the object<br />

delegates are recursively checked. This method mu<strong>st</strong> be generated by the compiler.<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

107


108<br />

This implementation ensures that any changes in the signature of an object is noticed, for<br />

in<strong>st</strong>ance if an internal object is replaced by another object (behavior injection). However,<br />

it has a computational overhead, as every time the signature needs to be calculated. This<br />

could be reduced by <strong>st</strong>oring the operations which an object indirectly supports (i.e. the<br />

signatures of the objects to which it delegates) at in<strong>st</strong>ance creation time. In<strong>st</strong>ead of sending<br />

the signatureIncludes: message to the object to be checked, this so called<br />

signature cache can be consulted to see if it includes the (selector of the) message.<br />

This signature caching technique requires additional effort to keep the cache consi<strong>st</strong>ent<br />

when the signature of an object changes (e.g. due to behavior injection). This is because<br />

the signature of a object (recursively) depends on the signatures of the object to which it<br />

dispatches. These dependencies can be expressed by a dependency tree. A change in the<br />

signature of an object requires all the objects towards the root of the dependency tree need<br />

to be notified to update their signature cache accordingly.<br />

12.4 Filter handler classes<br />

Every subclass of class Filter implements a specific filter handler. Figure 12-8 shows<br />

the filter handler hierarchy. If a message is rejected by a dispatch filter, send filter or meta<br />

filter, or accepted by a wait filter or error filter, the message mu<strong>st</strong> be filtered by the<br />

following filter. This means that the message does not leave the filter group. In the<br />

opposite cases, the message either leaves the filter group temporarily or definitely. As<br />

described in section 12.3.1, the filter signifies this by calling the leaveInput or<br />

leaveOutput method of the owning object, depending on whether it resides in the input<br />

or output filter group. To avoid case te<strong>st</strong>ing in the accept or reject action for this, we have<br />

introduced two separate subclasses for mo<strong>st</strong> filter handlers. The DispatchFilter and<br />

SendFilter have a single subclass because they can only appear as input filter or output<br />

filter, respectively. The problem of excessive class declarations (see section 1.1, page 3) is<br />

not so severe, because two classes are needed for each filter handler at mo<strong>st</strong>.<br />

FIGURE 12-8 The filter handler hierarchy<br />

DispatchFilter<br />

InputDispatchFilter<br />

SendFilter<br />

OutputSendFilter<br />

As we have mentioned in the previous section, a filter filters a message by performing the<br />

accept te<strong>st</strong> (evaluating the conditions, and collecting a new target and selector), and<br />

subsequently carrying out its accept or reject action, as appropriate. In the coming sections<br />

we describe these actions for each filter handler class in more detail. Note that if a message<br />

is accepted or rejected, the message leaves the filter group definitely, or only temporarily.<br />

In order to prevent deadlock, it mu<strong>st</strong> yield the group to the next active message (by<br />

leaveInput or leaveOutput), before further action is taken upon it.<br />

12.4.1 Dispatch filter<br />

When a message is accepted by a dispatch filter, it leaves the (input) filter group definitely.<br />

A new selector replaces the selector of the accepted message. If the new target is inner, a<br />

corresponding method of the owner will be invoked. The way how a method is invoked is<br />

Chapter 12: Execution Model<br />

Filter<br />

ErrorFilter<br />

InputErrorFilter InputMetaFilter InputWaitFilter<br />

OutputErrorFilter<br />

MetaFilter WaitFilter<br />

OutputMetaFilter<br />

OutputWaitFilter


described in section 12.5. Otherwise the message is offered to the input filters of the new<br />

target object. The message is directed to the input filters of this object by calling its<br />

inputMessage: method.<br />

12.4.2 Error filter<br />

A message which is accepted by an error filter is allowed to continue in the next filter. The<br />

new target or selector replace the receiver and selector of the accepted message,<br />

respectively. A rejected message leaves the filter group definitely and is aborted by raising<br />

the error filter error signal.<br />

12.4.3 Send filter<br />

When a send filter accepts a message, the message leaves the (output) filter group<br />

definitely. The new target or selector replace the receiver and selector of the accepted<br />

message. If the encapsulating object of the owner of the filter 5 does not encapsulate the<br />

target of the accepted message (i.e. if the target lies outside the encapsulating object of the<br />

owner), the message is directed to the output filters of the encapsulating object with the<br />

outputMessage: method. Otherwise it is directed to the input filters of target of the<br />

message with the aid of the inputMessage: method.<br />

12.4.4 Meta filter<br />

When a message is accepted by a meta filter, it leaves the filter group temporarily to be<br />

reified and offered to an ACT object. The new target and selector, and the reified active<br />

message are the receiver, selector and argument of a new active message for the ACT.<br />

Section 12.6 focuses on this. After the accepted message has been dereified, it mu<strong>st</strong><br />

continue in the following filter, except if the ACT supplied a reply for it, in which case the<br />

message does not have to enter the group again. As described in section 12.3.1, the active<br />

message reenters the filter group by sending enterInputAgain: or<br />

enterOutputAgain: to the owner of the filter. However, we do not have to account<br />

for messages which have been supplied a reply, because if this happens, the replyBlock<br />

block closure of ActiveMessage has been executed to shortcut the filtering process<br />

(see section 12.2)<br />

12.4.5 Wait filter<br />

A message that is accepted by a wait filter is allowed to continue in the next filter. A new<br />

target object and selector are discarded by this filter. A rejected message mu<strong>st</strong> be delayed,<br />

and therefore only temporarily leaves the filter group. The block closure containing the<br />

conditions on which the message was rejected (see section 12.3.2) is retrieved and is used<br />

to delay the message. This is described in section 12.7. After the message is allowed to<br />

continue, it reenters the filter group by sending enterInputAgain: or<br />

enterOutputAgain: to the owner of the filter.<br />

12.5 Method invocation<br />

The active message has finally arrived at a method which mu<strong>st</strong> be invoked. As we have<br />

seen in chapter 7 (section 7.6, page 50), there are two types of method, methods that return<br />

early and normal methods. With an early returning method it is possible to create<br />

concurrency. In the next chapter (section 13.3, page 121) we describe how to detect<br />

whether a method returns early or not. Since the object manager keeps track of how many,<br />

and which methods are active, this information mu<strong>st</strong> be passed to the object manager upon<br />

the invocation and the finishing of a method.<br />

A <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> method xyz(arg1, arg2, …, argn) is translated to a Smalltalk method which looks<br />

like this:<br />

5. An object knows its encapsulating object. For this, class Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object has an in<strong>st</strong>ance variable,<br />

called encapsulatingObject, to maintain this link<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

109


110<br />

EXAMPLE 12-7 A xyz: sender with: server with: arg1 with: arg2 … with: argn<br />

| temps |<br />

creation of temps<br />

body<br />

In<strong>st</strong>ances of the local variables of a method (declared in the temps section) are created<br />

before the body is executed. The parameters of the translated method correspond to the<br />

arguments as they are <strong>st</strong>ored in an ActiveMessage in<strong>st</strong>ance (see section 12.2). The fir<strong>st</strong><br />

two parameters, sender and server are always passed to the method. Thus, if the<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> method does not have any parameters, the header of the translated Smalltalk<br />

method is xyz: sender with: server.<br />

To invoke this translated <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> method, Smalltalk provides an operation<br />

perform:withArguments: which has the selector of the method to be invoked and<br />

an array of arguments as parameters 6 . The arguments are available as array in the<br />

ActiveMessage, but the selector #xyz:with:with:with:…with: is not. Only a<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong> equivalent selector is <strong>st</strong>ored in the ActiveMessage (the symbol #xyz in this<br />

case), which means that we mu<strong>st</strong> map the <<strong>st</strong>rong>Sina</<strong>st</strong>rong> selector to the Smalltalk selector. Every<br />

compiled <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> class therefore has a hash table which takes care of this mapping. The<br />

hash table is an in<strong>st</strong>ance of the Smalltalk class Dictionary and appears as the class<br />

variable <<strong>st</strong>rong>Sina</<strong>st</strong>rong>SmalltalkSelectorMap in the compiled class.<br />

The Smalltalk selector depends on the number of arguments of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> method. We<br />

could have <strong>st</strong>ored the Smalltalk selector in the ActiveMessage because the number of<br />

arguments is known at the moment of send. However, during the filtering of the message<br />

its selector mu<strong>st</strong> be compared several times with selectors specified in the filter initializer 7 .<br />

But the number of arguments is not known when the filter is declared, and consequently a<br />

Smalltalk selector cannot be used by the filter. To avoid complicated selector comparison<br />

during the filtering, the short <<strong>st</strong>rong>Sina</<strong>st</strong>rong> selector is <strong>st</strong>ored in the ActiveMessage, and used by<br />

filters. This <<strong>st</strong>rong>Sina</<strong>st</strong>rong> selector is also useful when the selector or the number of arguments of a<br />

message is changed by an ACT: the number of arguments does not have to be considered<br />

when these changes are applied to the message.<br />

Active method counters In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> , the object manager of an object keeps track of how many, and which methods of<br />

the object are active, that is, the methods which have been invoked and which have not<br />

finished their execution. A normal returning method finishes execution when it returns an<br />

object. An early returning method, on the other hand, continues after it has returned an<br />

object, until the la<strong>st</strong> <strong>st</strong>atement in the body has been executed. For this, the class<br />

ObjectManager represents the object manager of an object, and provides the methods<br />

<strong>st</strong>artedMethod: and finishedMethod:. These methods both take a (<<strong>st</strong>rong>Sina</<strong>st</strong>rong>)<br />

selector as an argument to indicate the method that <strong>st</strong>arts or ends. Upon the invocation of a<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> method, the former is called. Signalling the end of a method depends on whether<br />

the method returns early or not. The next section discusses this.<br />

The invocation of the method is carried out in the accept action of a dispatch filter. This<br />

filter decided that the accepted active message mu<strong>st</strong> be delegated to inner. This is shown<br />

below: the accept action converts the <<strong>st</strong>rong>Sina</<strong>st</strong>rong> selector in the active message to the Smalltalk<br />

selector of the method to be invoked, and signals the object manager that it <strong>st</strong>arts a<br />

method. It subsequently invokes the method, and passes the object returned from this<br />

method back to the active message, by calling its replyValue: method (see<br />

section 12.2).<br />

EXAMPLE 12-7 B DispatchFilter>>accept: activeMessage<br />

|sinaSel smalltalkSel|<br />

6. The perform:withArguments: method achieves (Smalltalk) message sending, as if a message with<br />

the involved selector and arguments had been sent to the receiver of the perform:with-Arguments:<br />

message. Normal (Smalltalk) method lookup and invocation takes place.<br />

7. Actually, an entry of the selector-dictionary is retrieved, see section 12.3.2.<br />

Chapter 12: Execution Model


sinaSel := activeMessage selector.<br />

smalltalkSel := object sinaSmalltalkSelectorMap at: sel.<br />

object manager <strong>st</strong>artedMethod: sel.<br />

activeMessage replyValue:<br />

(object<br />

perform: smalltalkSel<br />

withArguments: activeMessage arguments)<br />

12.5.1 Normal and early returning methods<br />

There are two types of methods, methods that return early and normal methods. The next<br />

chapter (section 13.3, page 121) describes how to detect whether a method returns early or<br />

not. When a method finishes, the object manager of its owner mu<strong>st</strong> be signalled in order to<br />

update its active method counters. A normal method finishes executing when it returns an<br />

object to its caller. An early returning method continues executing after it has returned an<br />

object to the caller, and it does this concurrently with the caller. This means that a new<br />

thread mu<strong>st</strong> be created upon the invocation of such a method. We now describe how both<br />

types of methods are translated to Smalltalk.<br />

FIGURE 12-9 Interaction diagram of the invocation of a normal method<br />

message<br />

thread<br />

sender<br />

reply<br />

Normal return Translation of a normal returning method is <strong>st</strong>raightforward, as example 12-7 C shows.<br />

Note that the reply expression is evaluated before the object manager decrements the<br />

active counter. Figure 12-9 shows the interaction diagram of the method invocation.<br />

EXAMPLE 12-7 C xyz: sender with: server with: arg1 with: arg2 … with: argn<br />

| temps |<br />

creation of temps<br />

<strong>st</strong>atements<br />

^manager finishedMethod: #xyz reply: expression.<br />

Early return Definition 7-2 prescribes a method to be an early returning method if there is a flow in<br />

which the return is followed by one or more <strong>st</strong>atements. There are several flows possible in<br />

a method, because the method body can contain <strong>st</strong>atements which do a branch (conditional<br />

if-then-else <strong>st</strong>atement and loop <strong>st</strong>atements). If we allow only one exit (return) from a<br />

method, it would be sufficient for an early returning method to create only a new thread for<br />

the <strong>st</strong>atements following the exit. Since a method can have several flows and equally<br />

multiple exits, it would require to create new threads for the <strong>st</strong>atements following a return<br />

in all possible flows. This is a problem because flows are difficult to calculate. For<br />

example, the <strong>st</strong>atements following a conditional <strong>st</strong>atement mu<strong>st</strong> be executed after the<br />

<strong>st</strong>atements in either branch. The solution is to create a new thread for the whole method<br />

body of an early returning method, as shows in example 12-7 D.<br />

EXAMPLE 12-7 D xyz: sender with: server with: arg1 with: arg2 … with: argn<br />

| temps reply hasReply |<br />

creation of temps<br />

hasReply := Semaphore new.<br />

manager newThreadFor:<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

ActiveMessage DispatchFilter receiver ObjectManager<br />

replyValue:reply<br />

filter:<br />

<strong>st</strong>artedMethod:<br />

perform:withArgs:<br />

reply<br />

finishedMethod:reply:<br />

reply<br />

111


112<br />

[ <strong>st</strong>atements preceeding a return<br />

reply := expression. hasReply signal.<br />

<strong>st</strong>atements following a return<br />

manager finishedMethodThread: #xyz.<br />

].<br />

hasReply wait.<br />

^reply<br />

The creation of a new thread is delegated to the object manager. The method (actually the<br />

invoking thread) mu<strong>st</strong> wait until a reply becomes available from one of the return<br />

<strong>st</strong>atements in the body thread. The translated method additionally has a semaphore and a<br />

shared variable to synchronize the invoking and the body thread. Only at the end of body<br />

thread, the object manager is signalized that the method and its thread have finished (see<br />

figure 12-10).<br />

FIGURE 12-10 Interaction diagram of the invocation of an early return method<br />

ActiveMessage DispatchFilter receiver ObjectManager<br />

message<br />

sender<br />

thread<br />

hasReply<br />

new<br />

thread<br />

reply<br />

12.6 Message reification and dereification<br />

Message passing semantics of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> has been described in chapter 10. When an object<br />

(sender) sends a message, the message will be filtered and, in mo<strong>st</strong> cases, invoke a method<br />

which returns an object to the sender. The execution path of this active message can be<br />

divided in what we call a forward travel and a backward travel. During the forward travel<br />

the message is being filtered in order to invoke and execute a method. This method yields<br />

an object which is returned to the sender during the backward travel. A meta filter can<br />

suspend the active message when it is filtered, i.e. during its forward travel. The message<br />

is reified and offered to an ACT. After the ACT has processed the message, the ACT<br />

dereifies it, which in general causes the message to travel further forward. The ACT can<br />

choose to suspend the execution again when the message is travelling backward, i.e. when<br />

it is returning a reply object to the sender. This allows the ACT to obtain the reply of the<br />

message and even change it. The ACT dereifies it a second time which causes the message<br />

to travel further backward with the original reply or indeed another.<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> , the class ActiveMessage represents an active message, that is, a message which<br />

is either being filtered, or executing a method. The class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message represents a reified<br />

message, that is, a message which is not executing. This can mean that it has not been<br />

active before, or that its was active but its execution (temporarily) has been suspended.<br />

The latter is the case if an active message was reified by a meta filter. In the former case,<br />

the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message in<strong>st</strong>ance is created because it was declared as an in<strong>st</strong>ance of that class.<br />

The class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message provides three methods to (re)activate, i.e. to dereify it. They are:<br />

• continue (synonym for fire), which causes the message to follow it normal course,<br />

either further forward or backward;<br />

Chapter 12: Execution Model<br />

replyValue:reply<br />

filter:<br />

<strong>st</strong>artedMethod:<br />

perform:withArgs:<br />

reply<br />

wait<br />

signal<br />

reply<br />

newThreadFor:<br />

finishedMethodThread:


• reply, which supplies a reply object for the message. It terminates further forward<br />

execution of the message and <strong>st</strong>arts the backward travel of the message, or when it<br />

already was on its return trip, sends it further back.<br />

• send, which causes the message to continue on its forward travel, and to intercept it<br />

when it is on its way back.<br />

A reified message, a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message in<strong>st</strong>ance, can pass through a number of <strong>st</strong>ages while it<br />

is reified. This is shown by the <strong>st</strong>ate diagram of figure 12-11. A reified message <strong>st</strong>arts<br />

either as being ACTIVE or IDLE. The latter indicates that is has not been active before, i.e.<br />

that it is a newly created <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message in<strong>st</strong>ance. The <strong>st</strong>ate ACTIVE means that the reified<br />

message was active before it was reified by a meta filter. If an ACTIVE reified message<br />

receives a send reque<strong>st</strong>, its <strong>st</strong>ate changes to HASREPLY (after it is temporarily dereified to<br />

obtain a reply object). This indicates that a reply is available. If it subsequently receives a<br />

continue reque<strong>st</strong>, this reply object is returned to the sender of the message. If in<strong>st</strong>ead it<br />

receives a reply reque<strong>st</strong>, the argument object of this reque<strong>st</strong> is returned to the sender. In<br />

both cases, the <strong>st</strong>ate changes from HASREPLY to REPLIED. This <strong>st</strong>ate is also reached if an<br />

ACTIVE reified message was supplied a reply object with reply at once. An ACTIVE reified<br />

message obtains the <strong>st</strong>ate UNREPLIED after it was dereified with continue. This <strong>st</strong>ate<br />

indicates that the message has not yet received a reply. If an IDLE reified message receives a<br />

send reque<strong>st</strong>, it is activated for the fir<strong>st</strong> time, and executes until it returns a reply. Its <strong>st</strong>ate<br />

therefore becomes REPLIED.<br />

FIGURE 12-11 State diagram of a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message<br />

ACTIVE<br />

send<br />

HASREPLY<br />

Other dereification reque<strong>st</strong>s in various <strong>st</strong>ates are not allowed. They are not shown in<br />

figure 12-11. For example, it is incorrect to send a reply reque<strong>st</strong> to a message in the <strong>st</strong>ate<br />

REPLIED. The final <strong>st</strong>ates UNREPLIED and REPLIED are the <strong>st</strong>ates in which the message<br />

becomes dereified and active again. In these <strong>st</strong>ates, it is not allowed to change the<br />

attributes of a message (sender, server, receiver, selector and arguments), although it is<br />

permitted to retrieve them.<br />

FIGURE 12-12 Object diagram of a reified message<br />

<strong>st</strong>ate<br />

reply<br />

continue<br />

reply<br />

continue<br />

reply<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message<br />

continue<br />

reply:<br />

send<br />

waitForDereify<br />

¤ reifiedFrom:<br />

UNREPLIED<br />

REPLIED<br />

Implementation The <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> classes ActiveMessage and <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message have direct Smalltalk counterparts in<br />

the implementation (see the object diagram of figure 12-12). In section 12.2 we already<br />

encountered class ActiveMessage. This class further provides the method reify in<br />

order reify itself, i.e. to create an in<strong>st</strong>ance of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message. The class method<br />

reifiedFrom: of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message accomplishes the in<strong>st</strong>ance creation by encapsulating<br />

the active message. The attributes <strong>st</strong>ate and reply are used to hold its <strong>st</strong>ate (as<br />

described above) and the reply object from a reply or send dereification reque<strong>st</strong>. The class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message additionally provides the dereification methods continue, reply:<br />

and send, and the method waitForDereify which blocks its active message<br />

component until it is dereified. For this, the semaphore attribute of class<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

send<br />

wait<br />

signal<br />

reify<br />

IDLE<br />

ActiveMessage<br />

semaphore<br />

113<br />

LEGEND<br />

START STATE<br />

FINAL STATE


114<br />

ActiveMessage is used which was also employed to block it if it enters an occupied<br />

filter group.<br />

The implementation of the dereification method send is <strong>st</strong>raightforward for an IDLE reified<br />

message: its active message component is presented to the input filters of its server<br />

(inputMessage:). The other to dereification methods are not applicable to an IDLE<br />

message.<br />

Reification and dereification of active messages is explained now. Figure 12-13 shows<br />

how a meta filter reifies an accepted active message. It creates an ACTIVE <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message<br />

by sending reify to the active message. The meta filter then reque<strong>st</strong>s the object manager<br />

of the receiver to create a new thread in which the ACT message is sent, having the reified<br />

message as argument. This new thread is needed because the ACT is allowed to continue<br />

concurrently with the message after the ACT has dereified it. Then the reified message is<br />

asked to wait until it is dereified (waitForDereify). This blocks the message thread.<br />

FIGURE 12-13 Interaction diagram of message reification and dereification<br />

message<br />

thread<br />

receiver<br />

(manager) MetaFilter ActiveMessage <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message ACT<br />

At some point in time, the ACT dereifies the message by sending one of the three<br />

dereification messages to the reified message. All the three ways of dereification<br />

accomplish this by signalling the active message. As a result, the message thread continues<br />

at the waitForDereify method. Depending on whether the message was supplied a<br />

reply while it was reified (<strong>st</strong>ate REPLIED/UNREPLIED), either the waitForDereify<br />

method finishes (marked with 1 ), or the active message replyValue: method is called<br />

(marked with 2 ). The former causes the message to be filtered by the next filter, while the<br />

latter transfers the execution back to the point where the message was sent (as described in<br />

section 12.2). We now look at the three dereification methods in more detail.<br />

FIGURE 12-14 Interaction diagram of dereification with continue<br />

Dereification with<br />

continue<br />

message<br />

thread<br />

receiver<br />

newThreadFor: [...]<br />

The interaction diagram of figure 12-14 shows the effect of dereification with continue.<br />

The top of the diagram displays the point where the message was blocked. If the<br />

Chapter 12: Execution Model<br />

1<br />

reify<br />

reifiedFrom:<br />

reifiedMessage a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message<br />

waitForDereify<br />

2<br />

wait<br />

signal<br />

ACTIVE<br />

replyValue: reply<br />

dereification<br />

Filter ActiveMessage <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message ACT<br />

wait<br />

REPLIED/UNREPLIED<br />

signal<br />

1<br />

4<br />

continue<br />

ACT<br />

thread<br />

ACT<br />

thread


continue reque<strong>st</strong> takes place immediately after the message became reified, i.e. if it is<br />

on its forward travel and its <strong>st</strong>ate is ACTIVE, it changes the <strong>st</strong>ate to UNREPLIED. If the<br />

continue reque<strong>st</strong> followed a send reque<strong>st</strong> (i.e. if it was on its backward travel and its<br />

<strong>st</strong>ate was HASREPLY) the <strong>st</strong>ate of the message becomes REPLIED. Subsequently, the active<br />

message is signalled which re<strong>st</strong>arts the message thread. The message then either continues<br />

forward in order to be filtered by the next filter (figure 12-13, marked with 1 ), or<br />

continues its backward travel. This is marked with 4 in figure 12-13, and is described<br />

below at dereification with send in more detail.<br />

FIGURE 12-15 Interaction diagram of dereification with reply:<br />

Dereification with<br />

reply:<br />

message<br />

thread<br />

Dereification with reply is shown in the interaction diagram of figure 12-15. The argument<br />

object of the reply reque<strong>st</strong> is <strong>st</strong>ored in the reply attribute of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message. The<br />

<strong>st</strong>ate of the message changes to REPLIED, and the active message is signalled. If the<br />

message was travelling forward, this is aborted, and it is sent backward in<strong>st</strong>ead ( 2 ,<br />

corresponding to figure 12-13). Otherwise it continues its backward journey ( 4 ).<br />

FIGURE 12-16 Interaction diagram of dereification with send<br />

message<br />

thread<br />

receiver<br />

Filter<br />

replyValue: x<br />

Dereification with send After a message has been dereified with send, it mu<strong>st</strong> be intercepted when a reply of the<br />

message becomes available, i.e. during its backward travel. This is realized by replacing<br />

the replyBlock block closure of the active message (see section 12.2) with one which<br />

transfers the control back to the ACT. When a reply becomes available, this block closure<br />

is executed in<strong>st</strong>ead. After the ACT dereifies the message a second time, the message<br />

continues its backward travel by executing the original reply block.<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

Filter ActiveMessage <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message ACT<br />

wait<br />

REPLIED(x)<br />

signal<br />

replyValue: reply<br />

2<br />

ActiveMessage <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message ACT<br />

wait<br />

getReplyBlk<br />

oldReplyBlk<br />

setReplyBlk: [...]<br />

3<br />

signal<br />

HASREPLY(x)<br />

wait<br />

signal<br />

4<br />

send<br />

wait<br />

signal<br />

reply<br />

dereification<br />

4<br />

reply: x<br />

hasReply<br />

115<br />

ACT<br />

thread<br />

ACT<br />

thread


116<br />

As shown by the interaction diagram for send (figure 12-16), the old reply block is<br />

preserved and replaced by the new one. Then, it signals the message to continue its<br />

forward travel, and blocks the ACT on the semaphore hasReply which causes to for the<br />

reply. In the mean time, the message is filtered by several other filters, invokes a method<br />

and returns a reply object (replyValue: x). This causes the new reply block to be<br />

executed ( 3 ). It <strong>st</strong>ores the reply object in the reply attribute of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message,<br />

changes the <strong>st</strong>ate to HASREPLY, and signals the ACT that a reply is available. Subsequently,<br />

the message blocks itself to wait until it is dereified again. The reply object is returned to<br />

the ACT as result of the send reque<strong>st</strong>. The ACT processes this object and after while<br />

sends a second dereification reque<strong>st</strong>. This continue or reply: reque<strong>st</strong> signals the<br />

message to proceed, as described above. The message then continues at 4 where it<br />

executes the original reply block, thus travelling further backward with the original reply<br />

object or a new reply object which was supplied by the reply: reque<strong>st</strong>.<br />

12.7 Synchronization<br />

Synchronization in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> is realized by the wait filter. If a wait filter rejects a message, it<br />

mu<strong>st</strong> be blocked. As the conditions on which it blocked reflect a <strong>st</strong>ate of an object, these<br />

conditions mu<strong>st</strong> be monitored to observe a <strong>st</strong>ate change which would allow the message to<br />

continue. This means that they mu<strong>st</strong> be reevaluated repeatedly. The object manager of an<br />

object is responsible for all of this.<br />

Object manager The object manager is represented by the class ObjectManager (see figure 12-17).<br />

Because every <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> object has an object manager, it is a made an in<strong>st</strong>ance variable of the<br />

class Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object. The object manager <strong>st</strong>ores blocked messages in two<br />

queues (MessageQueue): one for messages that are blocked by an input wait filter<br />

(message reque<strong>st</strong>s), and one for those blocked by an output wait filter (message<br />

invocations). The number of blocked messages in each of these queues can be reque<strong>st</strong>ed<br />

by a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> application. The attributes blockedReq and blockedInv preserve these<br />

numbers, which thus avoids counting the message queues.<br />

Stored together with each message entry in the queues are the conditions on which the<br />

message blocked. These conditions are available as a block closure (see section 12.3.1).<br />

These conditions have to be reevaluated when appropriate. If a wait filter rejects a<br />

message, it sends the blockedReq:on: c.q. blockedInv:on: reque<strong>st</strong> to the<br />

receiver of the message. This object delegates it to its object manager.<br />

As we have described in section 12.5, the object manager provides methods to keep track<br />

of the number of activated (unfinished) methods, and the threads which are created upon<br />

the invocation of early return methods. The object manager is informed when a method is<br />

invoked (<strong>st</strong>artedMethod:), when it finishes (finishedMethod:reply:), and<br />

when a new thread mu<strong>st</strong> be created (newThreadFor:) or de<strong>st</strong>royed<br />

(finishedMethodThread:). The attribute active holds the total number of<br />

activated methods, while activeForMethod gives this for each of the methods of the<br />

owner.<br />

FIGURE 12-17 Object diagram of the object manager<br />

Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

blockedReq:on:<br />

blockedInv:on:<br />

UserDefinedObject<br />

Chapter 12: Execution Model<br />

ObjectManager<br />

active<br />

activeForMethod<br />

blockedReq<br />

blockedInv<br />

threads<br />

blockedReq:on:<br />

blockedInv:on:<br />

<strong>st</strong>artedMethod:<br />

finishedMethod:reply:<br />

newThreadFor:<br />

finishedMethodThread:<br />

2<br />

MessageQueue


Starting and finishing a method, and blocking a message causes changes in the <strong>st</strong>ate of the<br />

object. The object manager therefore reevaluates the conditions of the blocked messages at<br />

these moments. In both queues, only the fir<strong>st</strong> message to evaluate its conditions to true is<br />

removed from its queue and re<strong>st</strong>arted. The private method updated of class<br />

ObjectManager carries out this reevaluation.<br />

Synchronization This leads to the interaction diagram of figure 12-18 which shows the synchronization of a<br />

message rejected by an input wait filter. The diagram is identical for messages that are<br />

blocked by output wait filters, except that blockedReq:on: is replaced by<br />

blockedInv:on:. The rejected message and its blocking conditions are placed in the<br />

queue. Because the <strong>st</strong>ate was changed (blockedReq was incremented), the conditions of<br />

blocked messages mu<strong>st</strong> be reevaluated. Subsequently, the active message thread is<br />

blocked. Another thread that caused a <strong>st</strong>ate change reevaluates the conditions and detects<br />

that they now evaluate to true. The blocked message is removed from the queue and<br />

signalled to resume. This causes the message to be filtered by the filter following the wait<br />

filter.<br />

FIGURE 12-18 Interaction diagram of message synchronization<br />

message<br />

thread<br />

InputWaitFilter<br />

blockedReq:on:<br />

There is one limitation to the implementation described above. Reevaluation at the <strong>st</strong>art or<br />

end of a method, or upon blocking of a message is sufficient to detect changes in the <strong>st</strong>ate<br />

of the object manager (part of the <strong>st</strong>ate of its owning object), but not always changes in the<br />

total <strong>st</strong>ate of the object. If the <strong>st</strong>ate of an object changes without a change in the <strong>st</strong>ate of the<br />

object manager, reevaluation will not take place, whil<strong>st</strong> there might be blocked messages<br />

that could be re<strong>st</strong>arted. This can happen if no messages are blocked and no method <strong>st</strong>arts<br />

or ends, but there is at lea<strong>st</strong> one method active causing these changes. To illu<strong>st</strong>rate this,<br />

consider example 12-8. Assume that method m2 is the single active method. This method<br />

con<strong>st</strong>antly changes the <strong>st</strong>ate s1, and as it is in an infinite loop it does not finish. If the<br />

object further does not receive any messages (which possibly could be blocked by the wait<br />

filter f and cause a reevaluation), then messages that are blocked on condition c reflecting<br />

<strong>st</strong>ate s are not re<strong>st</strong>arted, even though they should.<br />

EXAMPLE 12-8 class XYZ interface<br />

inputfilters<br />

f : Wait = { c ~> m1 };<br />

...<br />

end;<br />

class XYZ implementation<br />

conditions<br />

c begin return s end<br />

methods<br />

m1 ...<br />

m2 begin<br />

while true<br />

begin<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

receiver ActiveMessage ObjectManager MessageQueue<br />

blockedReq:on:<br />

wait<br />

updated<br />

updated<br />

signal<br />

addLa<strong>st</strong>:<br />

remove:<br />

117<br />

other<br />

thread


118<br />

end<br />

s := false; for i := 1 to 1000000 begin end;<br />

s := true; for i := 1 to 1000000 begin end;<br />

end<br />

end<br />

[Bergmans94] describes an algorithm which can solve this problem. The algorithm<br />

identifies the locations where relevant <strong>st</strong>ate changes take place, which are the points where<br />

the conditions (of the blocked messages) need to be reevaluated. Another solution would<br />

be to let the object manager evaluate the blocked messages at a regular basis (a timeinterval),<br />

irrespective of <strong>st</strong>ate changes in the object or its object manager. This leads a<br />

computational overhead, especially if the <strong>st</strong>ate of an object does not change frequently.<br />

As the algorithm of [Bergmans94] is intended to reduce the frequency of condition<br />

evaluation and minimizes the computational co<strong>st</strong>s involved in the evaluation, it can be<br />

used also to improve the implementation of condition reevaluation described in this<br />

section. The algorithm finds the locations where <strong>st</strong>ate changes occur, and additionally<br />

minimizes the amount of condition evaluation code.<br />

12.8 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> messages to Smalltalk objects<br />

As Smalltalk comes with an extensive class library, we also want to use them in a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

application. For this it is necessary that each Smalltalk object knows how to respond to a<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> message. As described in section 12.1, only the entry points (methods)<br />

inputMessage: and signatureIncludes: are needed for this.<br />

Therefore, we add these methods to the class Object, the superclass of all Smalltalk<br />

classes 8 . The inputMessage: method converts the message selector to a Smalltalk<br />

selector and executes the corresponding method. The class in<strong>st</strong>ance variable<br />

smalltalkSelectorDictionary of class ActiveMessage holds a number of<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong> selectors that require a special mapping. These are selectors which mu<strong>st</strong> be mapped to<br />

binary Smalltalk selectors (add to +, times to *, etc.). The signatureIncludes:<br />

method merely checks if the object has a method with a Smalltalk selector corresponding<br />

to the one of the active message.<br />

This concludes the description of the execution model. The following chapter details how<br />

a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> object is mapped to Smalltalk.<br />

8. Adding methods to an exi<strong>st</strong>ing class in general considered bad practice, but we do it for performance<br />

reasons. Message dispatch (in the dispatch filter) otherwise requires a te<strong>st</strong> to see if the target is a Smalltalk<br />

object, and if so, convert the <<strong>st</strong>rong>Sina</<strong>st</strong>rong> message to a Smalltalk message and send this to the Smalltalk object.<br />

Chapter 12: Execution Model


13 Translation Model<br />

In the previous chapter we described the execution model which showed how messages<br />

follow their course from sender, through filters, and eventually to the method of the<br />

receiver. In this chapter we describe the translation model, which defines how each <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

object is translated to Smalltalk. We <strong>st</strong>art by describing the object model of the<br />

implementation (section 13.1). Then we focus on a number of subjects which need<br />

additional attention. Section 13.2 shows how <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> in<strong>st</strong>ances are created, while the next<br />

section describes how we can detect whether a method is an early or a normal returning<br />

method. The final section summarizes the mapping from <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> to Smalltalk and describes<br />

what the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> compiler has to generate when it compiles a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> class.<br />

13.1 General object model<br />

The object model of figure 13-1 shows the <strong>st</strong>ructural relations between the various classes<br />

of the implementation. Every user defined <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> object has been mapped to a<br />

corresponding Smalltalk class UserDefinedObject which inherits from the class<br />

Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object. This class provides common behavior for all translated <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

objects. As we have seen in the previous chapter (section 12.3 and 12.7), it embodies the<br />

ObjectManager and two MessageQueues for messages entering the input or output<br />

filter groups. The ObjectManager additionally has two MessageQueues which holds<br />

messages blocked by wait filters. Every UserDefinedObject has its own set of<br />

methods and conditions. These are mapped to Smalltalk methods which are represented by<br />

the class CompiledMethod. Additionally, a UserDefinedObject has its own set of<br />

input filters and output filters. They are represented by the filter handler class hierarchy<br />

(section 12.3 and 12.4). A UserDefinedObject may aggregate any number of<br />

internals and in<strong>st</strong>ance variables, and can refer to any number of externals.<br />

Apart from the UserDefinedObject class, the classes ObjectManager,<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object, <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message, ActiveMessage, and RecursiveActive-<br />

Message are <<strong>st</strong>rong>Sina</<strong>st</strong>rong> classes. This means that they are defined by <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> (see appendix A,<br />

‘<<strong>st</strong>rong>Sina</<strong>st</strong>rong> Class Interfaces’) and behave like composition filters objects. However, they do not<br />

inherit from the class Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object, because they do not require filters for<br />

their implementation. In order to handle active messages, they have an inputMessage:<br />

method whose task is to ‘filter’ the message and invoke an appropriate method (like in a<br />

user defined object, see example 12-3, page 103). For this, it retrieves from the class<br />

variable <<strong>st</strong>rong>Sina</<strong>st</strong>rong>SmalltalkSelectorMap the Smalltalk selector of the method to be<br />

invoked that corresponds to the selector of the active message (similar to method<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

119


120<br />

filter<br />

group<br />

blocked<br />

messages<br />

DispatchFilter<br />

invocation, section 12.5, page 109). These classes also provide the method<br />

signatureIncludes: for signature matching.<br />

FIGURE 13-1 Object Model of the Implementation<br />

2 2<br />

ObjectManager<br />

MessageQueue<br />

LEGEND<br />

method<br />

CompiledMethod<br />

InputDispatchFilter<br />

Library Class<br />

LinkedLi<strong>st</strong><br />

external<br />

OutputSendFilter<br />

UserDefinedObject<br />

condition<br />

CompiledMethod<br />

Object<br />

The class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object provides default behavior (from the application viewpoint)<br />

which includes printing on a text window. This text window is represented by the class<br />

ObjectWindow, which will not be opened (‘popped-up’) until text is written to it.<br />

13.2 In<strong>st</strong>ance creation<br />

During the creation of an in<strong>st</strong>ance of a class, the exi<strong>st</strong>ence of its externals is verified, the<br />

internals and in<strong>st</strong>ance variables are created, and the initial method is executed provided<br />

there is one. The class parameters are initialized with the argument objects supplied by the<br />

creator. The creating object is the object which encapsulates it, that is, the object of which<br />

Chapter 13: Translation Model<br />

internal<br />

in<strong>st</strong>var<br />

Filter<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

ObjectWindow<br />

Dictionary<br />

SelectorDictionary<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message<br />

Message<br />

MessageSend<br />

ActiveMessage<br />

Recursive-<br />

ActiveMessage<br />

SendFilter ErrorFilter<br />

MetaFilter<br />

WaitFilter<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong> Class<br />

Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

InputErrorFilter InputMetaFilter InputWaitFilter<br />

OutputErrorFilter<br />

OutputMetaFilter<br />

OutputWaitFilter


the new in<strong>st</strong>ance is an internal, in<strong>st</strong>ance variable, or local variable. Only if the in<strong>st</strong>ance is<br />

created in the main method, i.e. if it is a global object, the encapsulating object is the nil<br />

object.<br />

FIGURE 13-2 Object & interaction diagram for in<strong>st</strong>ance creation<br />

Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

encapsulating<br />

object UserDefinedObject Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

¤newIn:with:*<br />

encapsulatingObject<br />

initializeIn:with:*<br />

initializeIn<strong>st</strong>anceIn:<br />

initializeIn<strong>st</strong>anceIn:<br />

UserDefinedObject<br />

initializeIn:with:*<br />

initializeInputFilters<br />

initializeOutputFilters<br />

verifyExi<strong>st</strong>enceExternals<br />

con<strong>st</strong>ructIn<strong>st</strong>anceObjects<br />

¤ newIn:with:*<br />

Figure 13-2 shows the object diagram and interaction diagram of the in<strong>st</strong>ance creation<br />

process. The creating object sends to the class a newIn:with:* reque<strong>st</strong> with itself as<br />

encapsulating object, and zero or more class parameter objects as arguments. This creates<br />

a new in<strong>st</strong>ance to which it sends the initializeIn:with:* reque<strong>st</strong>. This method<br />

gives the class parameters variables its values. Subsequently, the<br />

initializeIn<strong>st</strong>anceIn: method runs by initializing the filters, verifying the<br />

exi<strong>st</strong>ence of externals, creating in<strong>st</strong>ances of internals and in<strong>st</strong>ance variables, and invoking<br />

the initial method. Note that filter initialization consi<strong>st</strong>s of filling the<br />

SelectorDictionary with block closures. This is done at in<strong>st</strong>ance level because the<br />

block closures mu<strong>st</strong> refer to entities (internals, conditions) within the context of the<br />

in<strong>st</strong>ance.<br />

13.3 Detecting if a method returns normal or early<br />

At compile-time it can be detected whether a method is an early return or a normal<br />

method. Definition 7-2, page 51, shows that a method returns early if there is a flow in<br />

which a return <strong>st</strong>atement is followed by other <strong>st</strong>atements. This could easily be detected if<br />

there is only one flow in the method, that is, if the <strong>st</strong>atements in the body would always be<br />

executed one after another. However, for making decisions (if-then-else) and repetitive<br />

executions (loops), we mu<strong>st</strong> allow conditional jumps to appear in a method. Depending on<br />

the condition of the jump its possible either to take the jump and move the execution to<br />

another <strong>st</strong>atement in the method, or ju<strong>st</strong> execute the <strong>st</strong>atements following the jump. A<br />

conditional jump thus spawns two new flows.<br />

Finding all the flows in a method is impossible because their number can be infinite<br />

(caused by loops). In<strong>st</strong>ead, we resolve the return kind of the method by scanning the<br />

<strong>st</strong>atement sequence in the method body, and update this as every <strong>st</strong>atement is processed.<br />

We keep the <strong>st</strong>ate of the <strong>st</strong>atements processed so far, and determine the new <strong>st</strong>ate which is<br />

based on the current <strong>st</strong>ate and the return kind of the processed <strong>st</strong>atement. Apart from<br />

determining the return kind of a method, we also want to verify the two control flow<br />

requirements (definition 7-3, page 51) which demand that every flow mu<strong>st</strong> contain one,<br />

and only one, return.<br />

A method body consi<strong>st</strong>s of a sequence of <strong>st</strong>atements. A <strong>st</strong>atement can be a return <strong>st</strong>atement<br />

(return expression), a conditional <strong>st</strong>atement (if-then-else), a loop <strong>st</strong>atement (for and<br />

while), an assignment or a message expression:<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

new in<strong>st</strong>ance<br />

initializeInputFilters<br />

initializeOutputFilters<br />

verifyExi<strong>st</strong>enceExternals<br />

con<strong>st</strong>ructIn<strong>st</strong>anceObjects<br />

initial<br />

121


122<br />

method-body ::= <strong>st</strong>atement-seq<br />

{<strong>st</strong>atement-seq.returnkind}.<br />

<strong>st</strong>atement-seq::= <strong>st</strong>atement-seq <strong>st</strong>atement<br />

{f seq (<strong>st</strong>atement-seq.returnkind,<strong>st</strong>atement.returnkind)}<br />

|<br />

{NORETURN}.<br />

<strong>st</strong>atement ::= return<br />

{RETURN}<br />

| conditional<br />

{conditional.returnkind}<br />

| loop<br />

{loop.returnkind}<br />

| assignment<br />

{NORETURN}<br />

| message-expression<br />

{NORETURN}.<br />

conditional ::= if condition then <strong>st</strong>atement-seq else <strong>st</strong>atement-seq end<br />

{f cond (<strong>st</strong>atement-seq then.returnkind, <strong>st</strong>atement-seq else.returnkind)}.<br />

loop ::= loop-header begin <strong>st</strong>atement-seq end<br />

{f loop (<strong>st</strong>atement-seq.returnkind)}.<br />

In the syntax above, we have indicated the return kind of each <strong>st</strong>atement between curly<br />

braces {}. For example, the return kind of a method-body (which determines the return kind<br />

of the method) is the return kind of its <strong>st</strong>atement-seq. The return kind of the <strong>st</strong>atementseq,<br />

conditional and loop depend on the <strong>st</strong>atement-sequence(s) they enclose. This is<br />

expressed by the functions f seq , f cond , and f loop which are defined below. Note that the<br />

return kind of a <strong>st</strong>atement-seq is based on the return kinds of the la<strong>st</strong> <strong>st</strong>atement and the<br />

previous <strong>st</strong>atements (a <strong>st</strong>atement-seq without the la<strong>st</strong> <strong>st</strong>atement). This corresponds to<br />

scanning process: the return kind of the processed <strong>st</strong>atements is updated with the return<br />

kind of the la<strong>st</strong> <strong>st</strong>atement.<br />

The return kind of a <strong>st</strong>atement can be NORETURN, RETURN, EARLY, UNBALANCED, or<br />

BALANCED. The return kind NORETURN means that the <strong>st</strong>atement does not do a return, as for<br />

example the assignment and message-expression. A <strong>st</strong>atement has the return kind RETURN<br />

if it does a non-early return, but if it does, its return kind is EARLY. A <strong>st</strong>atement is<br />

UNBALANCED if there are several flows possible in the <strong>st</strong>atement of which at lea<strong>st</strong> one does<br />

not do a return. An example of this is the conditional <strong>st</strong>atement in which only one branch<br />

performs a return. The <strong>st</strong>ate becomes BALANCED if there is a RETURNing <strong>st</strong>atement following<br />

it. A BALANCED <strong>st</strong>atement may not be followed by others <strong>st</strong>atements, because then it would<br />

be an early returning <strong>st</strong>atement in which there is a flow with two returns. To see this,<br />

consider again the conditional <strong>st</strong>atement with one returning branch. The flow which<br />

follows the returning branch would encounter the second return in the <strong>st</strong>atements<br />

following the conditional <strong>st</strong>atement while this is not allowed. .<br />

TABLE 13-1 The function f cond (<strong>st</strong>atement-seq then .returnkind,<strong>st</strong>atement-seq else .returnkind).<br />

then NORETURN UNBALANCED BALANCED RETURN EARLY<br />

NORETURN NORETURN UNBALANCED UNBALANCED UNBALANCED ERROR<br />

UNBALANCED UNBALANCED UNBALANCED UNBALANCED UNBALANCED ERROR<br />

BALANCED UNBALANCED UNBALANCED BALANCED BALANCED ERROR<br />

RETURN UNBALANCED UNBALANCED BALANCED RETURN EARLY<br />

EARLY ERROR ERROR ERROR EARLY EARLY<br />

Table 13-1 defines the function f cond which depends on the return kinds of the then and else<br />

branches. If one branch does a RETURN, and the other does NORETURN then the conditional<br />

<strong>st</strong>atement becomes UNBALANCED, because there is one flow possible in which there is no<br />

Chapter 13: Translation Model<br />

else


eturn. For the same reason, the conditional <strong>st</strong>atement becomes UNBALANCED too if one<br />

branch does a RETURN and the other is UNBALANCED, one is BALANCED and the other does<br />

NORETURN or is UNBALANCED, or one is UNBALANCED and the other does NORETURN. If one<br />

branch does a RETURN while the other is BALANCED, the conditional <strong>st</strong>atement is also<br />

BALANCED because it is unbalanced until the la<strong>st</strong> <strong>st</strong>atement in both branches. Other entries<br />

should speak for themselves<br />

Table 13-2 defines the function f loop which gives the return kind of a loop <strong>st</strong>atement (for or<br />

while). The body of a loop can be executed zero or more times, depending on the<br />

con<strong>st</strong>raints of the loop. The loop <strong>st</strong>atement becomes UNBALANCED if the body does a<br />

RETURN, or if the body is BALANCED or UNBALANCED. This is because in these cases there is a<br />

flow without a return if the body is executed zero times. If the body returns EARLY, it gives<br />

an ERROR because this is not allowed (see definition 7-5, page 52). Note that the function<br />

f loop can be modified if the loop body is executed at lea<strong>st</strong> once (e.g. a repeat-until loop), or<br />

if we can derive this from the con<strong>st</strong>raints of the loop.<br />

TABLE 13-2 The function f loop (<strong>st</strong>atement-seq body.returnkind).<br />

body floop NORETURN NORETURN<br />

UNBALANCED UNBALANCED<br />

BALANCED UNBALANCED<br />

RETURN UNBALANCED<br />

EARLY ERROR<br />

The function f seq indicates that the return kind of a <strong>st</strong>atement sequence depends on the<br />

return kind of the <strong>st</strong>atements so far and that of the current <strong>st</strong>atement. Initially, there is<br />

NORETURN. We could have defined f seq by a table, but the <strong>st</strong>ate diagram of figure 13-3<br />

shows it more clearly. A <strong>st</strong>ate is drawn as a rounded rectangle and has a label X which<br />

indicates the return kind of the <strong>st</strong>atement sequence up to the la<strong>st</strong> processed <strong>st</strong>atement is X.<br />

States are connected by arrows, called edges which have labels indicating the return kind<br />

of the next <strong>st</strong>atement. An Y-labeled edge leaves <strong>st</strong>ate labeled X and ends at the <strong>st</strong>ate labeled<br />

f seq (X,Y), the new <strong>st</strong>ate of the <strong>st</strong>atement sequence.<br />

FIGURE 13-3 Flow <strong>st</strong>ate changes for a <strong>st</strong>atement sequence f seq<br />

NORETURN<br />

LEGEND<br />

START STATE<br />

EARLY<br />

NORETURN<br />

The initial <strong>st</strong>ate of a <strong>st</strong>atement sequence is NORETURN. As long as the next <strong>st</strong>atement has<br />

NORETURN, it remains in this <strong>st</strong>ate. If the <strong>st</strong>atement does a RETURN, the <strong>st</strong>atement sequence<br />

has a RETURN. If in this <strong>st</strong>ate there is a <strong>st</strong>atement which does NORETURN, the we have<br />

detected an EARLY return, which is ok if there are more NORETURN <strong>st</strong>atements. However, if<br />

the <strong>st</strong>atement sequence in the EARLY or RETURN <strong>st</strong>ate is followed by a <strong>st</strong>atement in which<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

UNBALANCED<br />

NORETURN UNBALANCED<br />

RETURN BALANCED<br />

NORETURN<br />

EARLY RETURN BALANCED<br />

UNBALANCED<br />

BALANCED<br />

RETURN<br />

EARLY<br />

Y<br />

X fseq (X,Y)<br />

UNBALANCED<br />

BALANCED<br />

RETURN<br />

EARLY<br />

ERROR<br />

EARLY<br />

UNBALANCED<br />

NORETURN<br />

RETURN<br />

BALANCED<br />

NORETURN<br />

UNBALANCED<br />

BALANCED<br />

RETURN<br />

EARLY<br />

123


124<br />

there is a return (UNBALANCED, BALANCED, RETURN, EARLY), this leads to the error <strong>st</strong>ate,<br />

because there is a second return in the same flow. The <strong>st</strong>atement sequence <strong>st</strong>ate changes<br />

from NORETURN to UNBALANCED if there is an UNBALANCED <strong>st</strong>atement, for in<strong>st</strong>ance a<br />

conditional <strong>st</strong>atement in which only one branch does a return. The <strong>st</strong>ate then remains<br />

UNBALANCED if the next <strong>st</strong>atements do NORETURN, or are UNBALANCED. The <strong>st</strong>ate changes<br />

from UNBALANCED to BALANCED if the <strong>st</strong>atement always returns normally (RETURN or<br />

BALANCED).<br />

A method is an early return method if the return kind of the <strong>st</strong>atement- sequence of its<br />

body is EARLY, that is, if its final <strong>st</strong>ate was EARLY. It is a normal method if the final <strong>st</strong>ate is<br />

RETURN or BALANCED. Any other <strong>st</strong>ate are not allowed and will lead to a compile time error<br />

message, because in these <strong>st</strong>ates indicate that there is a flow without a return (NORETURN,<br />

UNBALANCED), or with more than one (ERROR). Note that all the <strong>st</strong>ates except ERROR are<br />

accept <strong>st</strong>ates for a <strong>st</strong>atement-sequence since the sequence can be part of another <strong>st</strong>atement.<br />

13.4 Mapping <<strong>st</strong>rong>Sina</<strong>st</strong>rong> to Smalltalk<br />

Table 13-3 defines the mapping of the various <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> entities to Smalltalk. As mentioned<br />

before, a user defined class UDO is translated to a subclass of Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

which has the same name UDO. To avoid entities which map to Smalltalk in<strong>st</strong>ance<br />

variables receiving the same name as in<strong>st</strong>ance variables in the Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

class, their names are prefixed with f (for filters), or x (for variables). At this moment,<br />

externals can only be global objects and therefore they are mapped Smalltalk globals. The<br />

names of methods and conditions are as described in section 12.5.<br />

TABLE 13-3 Mapping of <<strong>st</strong>rong>Sina</<strong>st</strong>rong> entities onto Smalltalk entities.<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong> Smalltalk<br />

class UDO class UDO, subclass of Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

in<strong>st</strong>ance of class UDO in<strong>st</strong>ance of class UDO<br />

class parameter w of UDO in<strong>st</strong>ance variable xw of UDO<br />

external X of UDO global variable X<br />

internal y of UDO in<strong>st</strong>ance variable xy of UDO<br />

in<strong>st</strong>ance variable z of UDO in<strong>st</strong>ance variable xz of UDO<br />

filter group -<br />

filter f of UDO in<strong>st</strong>ance variable ff of UDO, an in<strong>st</strong>ance of a class<br />

from the filter handler hierarchy<br />

method m of UDO method m:with:with:* of UDO<br />

condition c of UDO method c: of UDO<br />

local variable of method m temporary variable of method m<br />

object manager of UDO in<strong>st</strong>ance variable manager of Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>-<br />

Object, an in<strong>st</strong>ance of class ObjectManager<br />

main method unbound method<br />

active message in<strong>st</strong>ance of class ActiveMessage<br />

recursive message in<strong>st</strong>ance of class RecursiveActiveMessage<br />

reified message in<strong>st</strong>ance of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message<br />

inner self<br />

self self<br />

server • attribute of class ActiveMessage<br />

• passed as parameter to method<br />

Chapter 13: Translation Model


TABLE 13-3 Mapping of <<strong>st</strong>rong>Sina</<strong>st</strong>rong> entities onto Smalltalk entities.<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong> Smalltalk<br />

sender • attribute of class ActiveMessage<br />

• passed as parameter to method<br />

message • in a condition: passed as parameter<br />

• in a method: implicitly available as selector and<br />

parameters of the method.<br />

The main method is translated to an unbound method 1 . An unbound method does not<br />

belong to a Smalltalk class: it is not <strong>st</strong>ored in the method dictionary of a class. An unbound<br />

method, say mu, can be executed by sending the message nil performMethod: mu.<br />

The pseudo variables inner and self are mapped to Smalltalk’s pseudo variable self.<br />

Messages to inner invoke the corresponding method directly without passing filters. This<br />

can be realized in Smalltalk by sending the corresponding (Smalltalk) message to self.<br />

This invokes the designated method.<br />

The pseudo variables sender and server are not represented directly but <strong>st</strong>ored in an<br />

ActiveMessage, or passed as parameter to an invoked method. The pseudo variable<br />

message is either represented directly (i.e. as ActiveMessage in<strong>st</strong>ance) as the<br />

parameter of a condition, or implicitly inside a method as the selector and arguments of<br />

this method<br />

We end this chapter by summarizing the attributes and methods which need to be<br />

generated by the compiler (see the next chapter) when it compiles a class. They are<br />

represented by the object diagram of figure 13-4 and the Smalltalk code below.<br />

FIGURE 13-4 Object diagram of a user defined object<br />

Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object subclass: #UserDefinedObject<br />

in<strong>st</strong>anceVariableNames: ‘filters classparams<br />

internals in<strong>st</strong>vars’<br />

classVariableNames: ‘<<strong>st</strong>rong>Sina</<strong>st</strong>rong>SmalltalkSelectorMap’<br />

poolDictionaries: ‘’<br />

category: ‘’<br />

UserDefinedObject methodsFor: ‘initial method’<br />

initial<br />

UserDefinedObject methodsFor: ‘interface methods’<br />

mi: sender with: server with: arg1 … with: argn<br />

1. The Smalltalk user interface also uses an unbound method to execute a group of <strong>st</strong>atements which are<br />

selected by the user for execution (do it), printing (print it) or inspection (inspect).<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

UserDefinedObject<br />

class parameters<br />

internals<br />

in<strong>st</strong>ance variables<br />

filters<br />

¤ <<strong>st</strong>rong>Sina</<strong>st</strong>rong>SmalltalkSelectorMap<br />

initializeIn:with:*<br />

initializeInputFilters<br />

initializeOutputFilters<br />

verifyExi<strong>st</strong>enceExternals<br />

con<strong>st</strong>ructIn<strong>st</strong>anceObjects<br />

inputMessage:<br />

outputMessage:<br />

signatureIncludes:<br />

methods<br />

conditions<br />

¤ newIn:with:*<br />

125


126<br />

UserDefinedObject methodsFor: ‘private methods’<br />

mp: sender with: server with: arg1 … with: argn<br />

UserDefinedObject methodsFor: ‘conditions’<br />

c: activeMessage<br />

UserDefinedObject methodsFor: ‘private-message handling’<br />

inputMessage: activeMessage<br />

outputMessage: activeMessage<br />

UserDefinedObject methodsFor: ‘private-signature matching’<br />

signatureIncludes: aSelector<br />

UserDefinedObject methodsFor: ‘private-initialization’<br />

initializeIn: encapsObj with: carg1 … with: cargn<br />

initializeInputFilters<br />

initializeOutputFilters<br />

verifyExi<strong>st</strong>enceExternals<br />

con<strong>st</strong>ructIn<strong>st</strong>anceObjects<br />

UserDefinedObject class<br />

in<strong>st</strong>anceVariableNames: ‘’<br />

UserDefinedObject class methodsFor: ‘in<strong>st</strong>ance creation’<br />

newIn: encapsObj with: carg1 … with: cargn<br />

Chapter 13: Translation Model


14 Programming<br />

environment<br />

The <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language implementation includes a programming environment. It is<br />

composed of a user interface, a compiler, and a kernel. The user interface allows the user<br />

to write, save, compile, and execute <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> applications. The compiler compiles source<br />

code into object code (Smalltalk). The kernel provides run-time support. In this chapter we<br />

describe these components.<br />

14.1 Compiler<br />

The compiler translates <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> source code to Smalltalk object code, in the way described<br />

in section 13.4, page 124. It is also responsible to report messages resulting from the<br />

compilation process. These compilation messages include error, warning, and information<br />

messages. While a compilation error causes the compiler not to generate Smalltalk code,<br />

the warnings and information messages are merely reported to the user.<br />

Figure 14-1 shows the <strong>st</strong>ructure of the compiler. The compiler is represented by the class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Compiler, which provides two methods to compile <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> source code. The<br />

method compile: takes a <strong>st</strong>ring containing the source code as an argument, compiles it,<br />

reports syntax errors and compilation messages, and if there are no errors, generates code<br />

for it. The method compileAndRun: additionally executes the main method, provided<br />

that the source code contained this method. Both methods return an in<strong>st</strong>ance of class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ProgramNodeHolder which holds the result of the compilation process (a parse<br />

tree). Normally, the compiler is invoked from the user interface (see next section) which is<br />

used to report compilation messages to. However, the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Compiler can also be used<br />

<strong>st</strong>and-alone, in which case Smalltalk’s Sy<strong>st</strong>em Transcript is used to report<br />

messages on.<br />

The <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Compiler is a three pass compiler. The fir<strong>st</strong> pass parses the source and builds<br />

a parse tree for it. A parse tree is an internal representation of the source program which is<br />

used in following phases. During the fir<strong>st</strong> phase, the syntax of the source program is<br />

checked. The location of a syntax error is shown in the source code window of the user<br />

interface, or, if the compiler has been used <strong>st</strong>and-alone, in a separate window which is<br />

popped up.<br />

The second pass performs various semantic checks, such as verifying that a variable has<br />

been declared, and that a message can be under<strong>st</strong>ood by a receiver object. Errors,<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

127


128<br />

warnings, and informatives from this phase are represented by the class<br />

CompilationMessage. They are <strong>st</strong>ored in the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Builder.<br />

During the final pass, the compiler generates Smalltalk code for the source program. This<br />

happens only if the previous phases did not yield a syntax error (fir<strong>st</strong> pass), or a semantic<br />

error (second pass) 1 . Every <<strong>st</strong>rong>Sina</<strong>st</strong>rong> class that appears in the source code is translated to a<br />

separate Smalltalk class. The main method is compiled into an unbound Smalltalk method.<br />

The parser, an in<strong>st</strong>ance of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Parser, is part of the compiler and is responsible<br />

for parsing the source code and building the parse tree. It is made up of a scanner and a tree<br />

builder. The scanner, an in<strong>st</strong>ance of the class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Scanner, breaks up the source code<br />

<strong>st</strong>ring into tokens. The tree builder, an in<strong>st</strong>ance of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Builder, assi<strong>st</strong>s the parser<br />

in building the parse tree, and is responsible to collect compilation messages resulting<br />

from the second compilation phase.<br />

FIGURE 14-1 Object model of the compiler<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Compiler<br />

compile:<br />

compileAndRun:<br />

CompilationMessage<br />

collects←<br />

We have used a tool called T-gen to create a scanner and a parser for the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language.<br />

T-gen (Translator Generator [Graver92a][Graver92b]) is a Smalltalk based tool for the<br />

automatic generation of scanners and parsers which handles all common grammars<br />

classified as LL(1), SLR(1), LALR(1) and LR(1). Using the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> token specification<br />

(appendix C.1), T-gen generates the scanner class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Scanner as a subclass of the Tgen<br />

library class OptimizedScanner-WithOneTokenLookahead. From the<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> grammar specification (appendix C.2), T-gen generates the parser class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Parser as subclass of the library class OptimizedLR1Parser.<br />

The fir<strong>st</strong> two passes, the syntactic and the semantic phase, do not take place one after<br />

another, but they have been intermingled. Once a complete class has been read from the<br />

source and a parse tree has been con<strong>st</strong>ructed for it (fir<strong>st</strong> phase), the semantics of the class is<br />

checked by the second phase 2 . Then, the following class or main part is read and<br />

semantically checked, until the complete source has been processed in this way. After this,<br />

the final phase generates Smalltalk code for the complete program, provided that no errors<br />

have been encountered.<br />

During parsing of the source program —the fir<strong>st</strong> pass of the compilation process— the<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Parser builds, with the aid of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Builder, a parse tree, holding the relevant<br />

information of the source program. The nodes of the parse tree are in<strong>st</strong>ances of classes<br />

which are not shown here. The result the compilation process is an in<strong>st</strong>ance of class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ProgramNodeHolder which holds the root of the parse tree, an in<strong>st</strong>ance of class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ProgramNode, and the semantic error messages.<br />

1. Warnings or informative messages from the second phase are no reason to skip code generation.<br />

2. What in fact takes place after the fir<strong>st</strong> pass has parsed the complete text of a class, is merging the information<br />

contained in the two parse tree nodes representing the class’ interface and implementation parts (an in<strong>st</strong>ance<br />

of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>InterfaceNode and <<strong>st</strong>rong>Sina</<strong>st</strong>rong>ImplementationNode respectively), into one node (a<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ClassNode) and then discarding the two former nodes.<br />

Chapter 14: Programming environment<br />

Ab<strong>st</strong>ractSyntax-<br />

TreeBuilder<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Builder<br />

OptimizedLR1Parser<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Parser<br />

OptimizedScanner-<br />

WithOneToken-<br />

Lookahead<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Scanner


14.2 User interface<br />

The user interface represented by the class Interactive<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Compiler which is a<br />

subclass of the sy<strong>st</strong>em class Model (see figure 14-2). The attribute source holds the<br />

source code that is edited by the user, while sourceFilename keeps the filename from<br />

which it was loaded. The source code is compiled by an in<strong>st</strong>ance of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Compiler, as<br />

described in the previous section. The attribute programNodeHolder holds the result<br />

of the compilation, which may contain a main method that is <strong>st</strong>ored in the mainMethod<br />

attribute to be able to run it at a later moment. The category attribute determines the<br />

category in Smalltalk’s sy<strong>st</strong>em dictionary in which a compiled class is <strong>st</strong>ored.<br />

FIGURE 14-2 Object model of the user interface<br />

The Interactive<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Compiler provides the class method open to create the user<br />

interface. It can be opened by sending the message open to the class, after which the<br />

window of figure 14-3 appears on the screen. The window has four subviews. They are:<br />

• the source code view, where the user can edit and compile source code;<br />

• the category view, that corresponds to the category attribute;<br />

• the transcript view, where the compiler reports what it is doing;<br />

• the compilation messages view, that displays errors, warnings and informative<br />

messages from the compilation process.<br />

The Interactive<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Compiler provides more (private) methods which are not<br />

described here.<br />

FIGURE 14-3 The user interface window<br />

category<br />

transcript<br />

compilation<br />

messages<br />

Interactive<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Compiler<br />

source<br />

sourceFilename<br />

programNodeHolder<br />

mainMethod<br />

category<br />

¤ open<br />

Model<br />

14.3 Kernel<br />

The kernel of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> development environment consi<strong>st</strong>s of several classes which are<br />

necessary to execute a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> application. Mo<strong>st</strong> of these classes have been explained in<br />

previous chapters of this thesis. They are<br />

• Ab<strong>st</strong>ract<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object, ObjectManager, MessageQueue;<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Compiler<br />

source<br />

code<br />

129


130<br />

Process scheduling<br />

in Smalltalk<br />

• ActiveMessage, RecursiveActiveMessage, <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message;<br />

• <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object, ObjectWindow;<br />

• SelectorDictionary, Filter, and the hierarchy of filter handler classes.<br />

In addition to these classes, the kernel provides a preemptive process scheduler which is<br />

described below.<br />

Smalltalk facilitates the control of multiple independent processes [Goldberg83]<br />

[ParcPlace92a], but only provides non-preemptive scheduling of processes, which may<br />

cause a single process to monopolize the processor. As <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> allows multiple concurrent<br />

threads (processes) and we want to prevent this from happening, we present a preemptive<br />

process scheduler.<br />

A process represents a sequence of actions that can be carried out independently of actions<br />

represented by other processes. A Smalltalk process, represented by the class Process,<br />

can be assigned a priority which allows to differentiate important tasks (e.g. keyboard<br />

input) from less significant ones (e.g. background printing). A new process can be created<br />

by sending the message fork to a block closure, a sequence of actions (messages) between<br />

brackets [].<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> , a thread is a sequence of actions (messages) which can execute concurrently<br />

with other threads. A thread is mapped to a Smalltalk process. Every <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> thread is<br />

assigned the priority called userScheduling-Priority. This is the same level at<br />

which in Smalltalk normal user interactions take place.<br />

A Smalltalk process can be in any of the four different <strong>st</strong>ates, suspended, waiting,<br />

runnable, or running. A running process, as the name indicates, is running on Smalltalk’s<br />

(virtual) Processor. As Smalltalk has a single Processor, only one process can be<br />

running. In the following four occasions the Processor reschedules the running process<br />

to give another process a chance to run:<br />

• if the running process terminates, i.e. when it executes its la<strong>st</strong> action. The process will<br />

cease to exi<strong>st</strong>;<br />

• if a process with a higher priority becomes runnable. The process will reoccupy the<br />

Processor if the higher priority process releases it, and there are no other runnable<br />

processes with a higher priority;<br />

• if the running process becomes suspended. This can happen when the running<br />

Process receives a suspend message either from itself, or another process3 . When<br />

it receives a resume message, its <strong>st</strong>ate changes to runnable again.<br />

• if the running process blocks on a semaphore. This can happen when it sends a wait<br />

message to the semaphore (in<strong>st</strong>ance of class Semaphore) for which there are no<br />

out<strong>st</strong>anding signal messages4 . The <strong>st</strong>ate of the blocked process becomes waiting. If<br />

another process sends a signal message to the semaphore, the process becomes<br />

runnable.<br />

The Processor chooses which of the runnable processes is allowed to run next. The<br />

highe<strong>st</strong> priority process takes precedence over other processes. Of the processes with equal<br />

priority, the process that was rescheduled by a higher priority process, if any, is served<br />

next. Otherwise, equal priority processes are scheduled in the order in which they became<br />

runnable.<br />

Smalltalk’s scheduling sy<strong>st</strong>em is non-preemptive, which means that the running process<br />

will not be rescheduled until one of the four events above occurs. If they never happen, the<br />

3. With a higher priority, see previous point.<br />

4. A process is blocked if it sends a wait message to the semaphore which did not receive a signal message<br />

yet. As the semaphore can receive more signal messages, a process which sends a wait to it is not<br />

blocked as long as there are ‘out<strong>st</strong>anding’ signal messages.<br />

Chapter 14: Programming environment


Preemptive process<br />

scheduler<br />

process monopolizes the Processor and does not give other runnable processes (of the<br />

same priority) a chance to run. In order to prevent this, each process mu<strong>st</strong> be suspended<br />

regularly 5 . The Processor provides the method yield for this which mu<strong>st</strong> be<br />

explicitly placed inside the (code of the) process at proper places. It is hard to decide<br />

where to put it, and additionally there is <strong>st</strong>ill the possibility that one process runs longer<br />

than another.<br />

Because in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> there can be several process (all with the same priority<br />

userSchedulingPriority) which all mu<strong>st</strong> get an equal chance to run, we have<br />

designed preemptive process scheduler which allows each process an equal amount of<br />

time (a time-slice) to run before it is rescheduled.<br />

Preemptive scheduling works by having a process (the rescheduling process) that<br />

preempts the running userSchedulingPriority process every time-slice seconds<br />

(currently 300 milliseconds). The rescheduling process therefore suspends it, and resumes<br />

it immediately afterwards, so that it is placed at the back of the li<strong>st</strong> of runnable processes<br />

of the same priority. The fir<strong>st</strong> process in this li<strong>st</strong> thereupon <strong>st</strong>arts to run. The rescheduling<br />

process works at userInterruptPriority level, which is higher than the<br />

userSchedulingPriority. In order not to monopolize the Processor, the<br />

rescheduling process suspends itself for time-slice seconds after it has performed a<br />

reschedule. With this, every runnable process gets an equal chance to run.<br />

The preemptive process scheduler is represented by the two classes<br />

RoundRobinScheduler and Sy<strong>st</strong>emScheduler (see figure 14-4). The latter<br />

provides behavior to in<strong>st</strong>all only a single scheduler (the global object called<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Scheduler) in the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> development environment, while its superclass<br />

implements the preemptive process scheduling (and is thus reusable for other<br />

applications). The method <strong>st</strong>op (temporarily) prevents processes from being preempted<br />

(thus reverting to Smalltalk’s non-preemptive scheduling), while the method <strong>st</strong>art<br />

resumes it.<br />

FIGURE 14-4 Preemptive process scheduler.<br />

<strong>st</strong>art<br />

<strong>st</strong>op<br />

RoundRobin-<br />

Scheduler<br />

This concludes the description of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation.<br />

5. And be resumed, so that it remains runnable.<br />

The Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

Sy<strong>st</strong>emScheduler<br />

¤ in<strong>st</strong>all<br />

¤ schedulerName<br />

131


132<br />

Chapter 14: Programming environment


PART<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong><br />

iv Evaluation and Conclusions<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language


134


Inconsi<strong>st</strong>encies in the<br />

filter syntax and<br />

semantics<br />

15 Evaluation<br />

This chapter evaluates the work presented in this thesis. The discussion in is divided in two<br />

parts, the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language, and its implementation.<br />

15.1 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language<br />

We evaluate the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language from a programmers viewpoint, and ask ourselves the<br />

que<strong>st</strong>ion if <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> contains any inconsi<strong>st</strong>encies that may cause confusion, and secondly,<br />

which con<strong>st</strong>ructs, c.q. functions could be added to <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> to improve the language.<br />

The semantics of a programming language should conceptually be clear and unambiguous<br />

to the programmer. It may be confusing if a certain language con<strong>st</strong>ruct behaves differently<br />

in comparable situations, or if some functionality is not provided. We identify the<br />

following three inconsi<strong>st</strong>encies in the filter semantics (also described in [vDijk95]):<br />

• The new target object and selector that may yield from the accept te<strong>st</strong> (see section 9.4,<br />

page 66) are used for different purposes by different filter handlers (section 9.6,<br />

page 69)<br />

The dispatch filter uses the new target as the object where to dispatch the message to,<br />

and the new selector to replace that of the accepted message. Similarly, the send filter<br />

uses both of them to replace the receiver and the selector of the message. The error<br />

filter also uses them to replace the receiver and the selector of the accepted message,<br />

but unlike the former two filters, the accepted message continues in the following filter,<br />

as the error filter causes an error on a rejected message. The dispatch, send and error<br />

filter thus effectively perform sub<strong>st</strong>itution on the message 1 .<br />

The meta filter uses the new target and selector as the receiver and selector of the ACT<br />

message which has the accepted, but reified message as argument. The wait filter, on<br />

the other hand, discards the new target and selector. These filter do not modify the<br />

accepted message.<br />

• As shown by the previous, three filter handlers have, in addition to their basic<br />

functionality, also a sub<strong>st</strong>itution functionality;<br />

• It is not possible to declare a meta filter that reifies only message which are supported<br />

by a single internal or external, i.e. messages that are in the signature of the object, and<br />

offer them to another (ACT) object;<br />

1. The new target and selector are for this reason also called the sub<strong>st</strong>itution target and selector.<br />

Evaluation and Conclusions<br />

135


136<br />

Useful extensions to<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

This is because it is not possible to specify the target and selector of the ACT message<br />

separately from the message matching: a signature pattern z.* would match the<br />

messages supported by z but the meta filter would offer the ACT message also to z,<br />

while a matching pattern [z.*]act.m only matches messages whose receiver is z.<br />

To overcome these problems we propose the following solutions (more extensively<br />

described in [vDijk95]):<br />

• Redefine the semantics of the various filter handlers, so that only the basic<br />

functionality of the filter remains. For the dispatch, send and error filter this means<br />

removing the sub<strong>st</strong>itution functionality;<br />

• The sub<strong>st</strong>itution functionality can be assigned to a new filter type, the sub<strong>st</strong>itution<br />

filter;<br />

• Identify for each filter what they require to perform their accept or reject actions, and<br />

introduce a new filter specification syntax which allows this to be specified.<br />

The dispatch filter only requires to know the object where to dispatch an accepted<br />

message. The meta filter requires a target object and a selector for the ACT message.<br />

The sub<strong>st</strong>itution filter needs to have a new target and selector to replace those of the<br />

accepted message. The send filter and the wait filter do not need extra information. An<br />

error filter does not need any information either, but the error filter could be extended<br />

to take for example the exception to be raised;<br />

A new filter syntax which adopts these changes has been described in [vDijk95] which<br />

also discusses more elaborately the inconsi<strong>st</strong>encies and proposed solutions.<br />

In addition to the changes ju<strong>st</strong> described, we present a few extensions to the language we<br />

feel could improve the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language:<br />

• The possibility to use block closures, similar to those in found in Smalltalk. A block<br />

closure is an object that represents a deferred sequence of actions. The sequence of<br />

actions a block closure describes takes place when it receives a message to evaluate<br />

itself. Block closures would make it less troublesome to apply Smalltalk’s library of<br />

Collection classes, as they use a block closure for their iteration.<br />

• An ACT can re<strong>st</strong>art a reified message, by using one of the dereification messages<br />

continue (synonym for fire), reply or send, but it cannot abort a reified message and<br />

thus return an error to the sender of the message.<br />

• An exception handling mechanism would be useful to handle and respond to errors that<br />

occur at run-time.<br />

15.2 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> has been implemented in Smalltalk according to part III of this thesis. We<br />

summarize the limitations of the implementation, the problems we have encountered and<br />

the bugs that are known at this moment. Finally, we compare the performance of the<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation with Smalltalk.<br />

15.2.1 Limitations<br />

The <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation has the following limitations:<br />

• It does not provide type checking.<br />

• Full scope rules have not been implemented. This means that the externals can only be<br />

global objects and not internals of an encapsulating object.<br />

• The real-time filter is not provided.<br />

• Data-base functionalities have not been implemented. Associative object access as<br />

described in [Aksit92] is thus not possible.<br />

Chapter 15: Evaluation


15.2.2 Encountered problems<br />

In part III, ‘Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language’, we discovered a number of problems<br />

related to signature of an object. They are summarized here.<br />

• We cannot detect, or only with great effort, if an ACT affects the signature of an object.<br />

• Although a message can be included in the signature of an object, this does not mean<br />

that the object at one moment supports a certain message. This can happen if at that<br />

moment the conditions in the dispatch filters of the object have values which prevent<br />

the message from being dispatched.<br />

The cause is that the signature of an object is based on the operations it supports<br />

(directly or indirectly) irrespective of the values of the conditions. A solution to this<br />

problem requires a more accurate definition of the signature. The conditions should be<br />

considered when a dispatch filter has to decide to dispatch a message to a certain target<br />

object. With a careful design, this should not need unnecessary condition evaluations.<br />

Note that a similar situation can occur if a message is delayed by a wait or meta filter.<br />

However, this is caused by the application because the <strong>st</strong>ate of the object changed has<br />

changed in between. The application (i.e. programmer) should take precautions to<br />

prevent this.<br />

• The current signature definition does not consider the number of arguments and the<br />

type of arguments of a message. If type checking is implemented this should, be<br />

supported as well.<br />

15.2.3 Known bugs<br />

Synchronization of messages by the wait filter <strong>st</strong>ill causes problems. The object manager<br />

reevaluates the conditions of blocked messages to see if they can be re<strong>st</strong>arted. Under<br />

certain conditions 2 , more than one message is re<strong>st</strong>arted, although the application only<br />

allows one to be re<strong>st</strong>arted. This can cause a chain of blocked messages that are re<strong>st</strong>arted.<br />

The likely origin of this problem is the mutual exclusion of the reevaluation process.<br />

Although we implemented this in a way which does not allow more than one thread<br />

(process) to evaluate the conditions, we did not prevent another thread to change the<br />

conditions 3 while a reevaluation is in progress. The object manager may erroneously<br />

decide to re<strong>st</strong>art the message. It requires further research on how to prevent this from<br />

happening.<br />

15.2.4 Performance comparison<br />

Although performance was not the focus of this thesis, we have made a comparison of the<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation with Smalltalk in order to identify any bottlenecks in the execution.<br />

We compare the performance of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation with Smalltalk by measuring the<br />

execution times of a single message send. The message does not have any arguments and<br />

invokes a method that returns nil. We make a difference between the case in which a local<br />

method is invoked, and if a ‘superclass’ method is invoked. For Smalltalk, this means a<br />

method of the direct superclass of the receiving object, while for <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> the message is<br />

dispatched to an internal object representing the superclass. This shows us the overhead of<br />

message dispatch of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> in comparison with Smalltalk’s method lookup (in the class<br />

hierarchy).<br />

Further, the receiving <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> object and its internal both have one filter, a dispatch filter,<br />

which does not have a condition. The message invoking the local method thus has to pass<br />

through one filter, and the message invoking the superclass method mu<strong>st</strong> pass two dispatch<br />

filters.<br />

2. Which we experienced when we te<strong>st</strong>ed the BoundedBuffer example, example 9-5 on page 70.<br />

3. Actually the <strong>st</strong>ate of an object, which is read by the conditions.<br />

Evaluation and Conclusions<br />

137


138<br />

In Smalltalk, a message send is handled by Smalltalk’s virtual machine, but the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

implementation creates a new object (an ActiveMessage in<strong>st</strong>ance) for each message<br />

which is sent. To compare this with a similar situation in Smalltalk, we additionally timed<br />

message sending in which each message is represented by a newly created object. Such a<br />

message is represented in Smalltalk by the class MessageSend. This message invokes<br />

the local method or the superclass method, in the same way as the plain Smalltalk message<br />

send.<br />

We have carried out the performance te<strong>st</strong> on a Sun SPARC<strong>st</strong>ation 10, and to avoid<br />

overhead of the preemptive process scheduler (section 14.3, page 129), it has been<br />

disabled. Table 15-1 presents the actual running times, for a single message send. The fir<strong>st</strong><br />

column shows the results of a <<strong>st</strong>rong>Sina</<strong>st</strong>rong> message send, the middle column displays the plain<br />

Smalltalk message send, while the la<strong>st</strong> column presents the Smalltalk message send<br />

represented by a newly created MessageSend object. The table shows that there is not a<br />

measurable difference between the invocation of a local and a superclass method, in both<br />

the Smalltalk versions. In the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation, however, dispatching the message to<br />

the internal representing the superclass co<strong>st</strong>s an additional 0.26 milliseconds, which is<br />

about one third of a message send invoking the local method.<br />

TABLE 15-1 Raw running times for a single message send<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong> (ms) Smalltalk (ms)<br />

Smalltalk with<br />

MessageSend<br />

(ms)<br />

Local message 0.74 0.00030 0.015<br />

Superclass message 1.0 0.00030 0.015<br />

The entries in the following table are the ratios of the running times of the benchmarks for<br />

a given pair of sy<strong>st</strong>ems. The fir<strong>st</strong> column shows that the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation is<br />

considerably slower than plain Smalltalk. This is partially caused by the creation of a<br />

message object for each message that is sent, and partially due to the filtering process. The<br />

second column compares <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> with Smalltalk which creates a message object for a<br />

message send, similar to the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation. This shows that <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> is a factor 50<br />

to 60 slower, which is caused by the filtering process. The la<strong>st</strong> column displays the effect<br />

of message object creation, as it compares plain Smalltalk with the version that does create<br />

a message object. If we elimininate the creation of a message object for each message<br />

send, then the performance can be improved with a factor 50.<br />

TABLE 15-2 Relative performance<br />

We are not surprised by the relative performance of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> , as the message object creation<br />

is likely to cause a considerable overhead. Additionally, the filtering process has been<br />

implemented with the aid of various Smalltalk methods which all mu<strong>st</strong> be executed. We<br />

expect that the following points would improve the performance of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> :<br />

• We should eliminate the creation of a message object each time a message is sent. This<br />

could be realized by implementing <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> in a <strong>st</strong>ack-oriented way, comparable to many<br />

programming languages, including Smalltalk.<br />

In this <strong>st</strong>ack-based implementation, the arguments of a message, its receiver, sender<br />

and selector are pushed onto an execution <strong>st</strong>ack. Each filter thus would need to access<br />

the <strong>st</strong>ack in order to decide to accept or reject the message. A method reads its<br />

arguments from the <strong>st</strong>ack and pops them of the <strong>st</strong>ack to replace it with the reply object<br />

if it finishes.<br />

Chapter 15: Evaluation<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong> / Smalltalk<br />

Smalltalk w.<br />

MessageSend /<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong> / Smalltalk w. MessageSend Smalltalk<br />

Local message 2.5 × 103 49 50<br />

Superclass message 3.3 × 10 3 66 50


• The filtering process causes an additional overhead and should be optimized to reduce<br />

this. We already applied an optimization, by considering for each filter which<br />

conditions need to be evaluated for each possible message that is filtered.<br />

We could optimize this further: in<strong>st</strong>ead of generating evaluation code for each filter<br />

separately, we should consider a filter group in total, and track down the possible<br />

path(s) a message follows through this group. The accept or reject action of each filter<br />

could be inlined in the con<strong>st</strong>ituting the filtering process for a single message. There is<br />

one difficulty with this approach: if a message passes a meta filter, we cannot be sure<br />

that the message is in the same <strong>st</strong>ate as before. An ACT could for example change the<br />

selector, after which the pathe of the message through the filters cannot be determined.<br />

• Additionally, the condition evaluation algorithm of [Bergmans94] can be applied to<br />

reduce the frequency of condition evaluation and minimizes the computational co<strong>st</strong>s<br />

involved in the evaluation.<br />

Evaluation and Conclusions<br />

139


140<br />

Chapter 15: Evaluation


16 Conclusions<br />

This chapter gives a brief overview of the work that has been presented in this thesis, the<br />

contributions we made, and future directions of research.<br />

16.1 Overview and contributions<br />

We follow the <strong>st</strong>ructure of this thesis and discuss the material in part II, ‘Definition of the<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language’, and part III, ‘Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language’.<br />

16.1.1 Definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language<br />

In chapters 2 to 10 we have laid down the definition of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language, by describing<br />

its syntax and semantics in an informal way. To illu<strong>st</strong>rate the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language, we<br />

presented numerous examples.<br />

Smalltalk classes and objects can be used in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> as if they are <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> classes c.q.<br />

objects. As <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> incorporates the composition filters object model, it can solve a number<br />

of software modelings problems described in chapter 1.<br />

Chapter 10 described message reification through a meta filter, which allows an<br />

application to reflect on the message communication between two objects. The meta filter<br />

reifies the message and offers it to an ACT object, which dereifies the message after it<br />

processed it. We introduced a new dereification method, called send, which allows the<br />

ACT to regain control over the message as soon as the reply object becomes available for<br />

it. The ACT thus obtains the reply of the message, and has even the possibility to replace it<br />

with another. With the two other dereification methods, continue (synonym for fire) and<br />

reply, the message follows its normal course, without the ACT taking control over the<br />

message or acquiring the reply of it.<br />

16.1.2 Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language<br />

In chapters 11 to 14 we have shown how <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> can be implemented in Smalltalk.<br />

Chapter 12 described the execution model by following a message from the moment it is<br />

sent, through being filtered, to the moment of method invocation.<br />

We use a fir<strong>st</strong>-class representation for an active message which allows filters to access the<br />

attributes of the message easily when they filter the message.<br />

Evaluation and Conclusions<br />

141


142<br />

If a filter filters a message it mu<strong>st</strong> decide whether to accept or to reject the message by<br />

evaluating the filter initializer. This message accept te<strong>st</strong>, according to its definition,<br />

considers each filter element in turn by evaluating the conditions, matching the selector,<br />

etc. To avoid unnecessary evaluation of conditions in the filter initializer (i.e. if the selector<br />

of the message does not match the one in the filter element), we introduced an algorithm<br />

which extracts from the filter initializer the conditions to be evaluated for a selector, and<br />

for that selector only.<br />

A filter is accordingly represented as a selector dictionary which is a hash table that<br />

contains for each selector a code block embodying the conditions to be evaluated. The<br />

accept te<strong>st</strong> consequently consi<strong>st</strong>s of retrieving the code block corresponding to the selector<br />

of the message and evaluating this code block. The code block is also used when a<br />

message is blocked by a wait filter. The code block is <strong>st</strong>ored along with the message when<br />

it blocks. In order to see if the message can be re<strong>st</strong>arted, it is reevaluated when a <strong>st</strong>ate<br />

change affecting the conditions occurs.<br />

The implemented signature matching scheme recognizes dynamic changes in the signature<br />

of an object.<br />

The implementation provides five types of filter handler: dispatch filter, error filter, send<br />

filter, wait filter, and meta filter. The accept and reject actions of these filter handlers are<br />

<strong>st</strong>raightforward, and are implemented without difficulty.<br />

The object manager keeps track of the active methods of an object, which means that its<br />

<strong>st</strong>ate mu<strong>st</strong> be updated whenever a method is invoked or finishes. With method invocation<br />

we mu<strong>st</strong> make a di<strong>st</strong>inction between normal and early returning methods. An early<br />

returning method creates a new concurrent thread which allows it to continue executing<br />

after it returned a reply object to the sender. We have mapped a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> thread to a<br />

Smalltalk process.<br />

A new concurrent thread is also created when a meta filter accepts a message, reifies it, and<br />

offers it to an ACT object. A reified message provides three methods to dereify it,<br />

continue, reply and send. We have shown how these methods can be implemented.<br />

Synchronization in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> is realized with a wait filter which blocks a message when it<br />

rejects it. The object manager is responsible to reevaluate the conditions on which the<br />

message blocked to see if it can be re<strong>st</strong>arted. The object manager performs this<br />

reevaluation whenever its <strong>st</strong>ate changes, that is, when a method <strong>st</strong>arts or finishes, or when<br />

a message blocks by a wait filter. This is not sufficient, since the <strong>st</strong>ate of the object<br />

manager is only a part of the total <strong>st</strong>ate of the owning object. A reevaluation should be<br />

done whenever a <strong>st</strong>ate changes. The algorithm described in [Bergmans94] can be used to<br />

find the locations where <strong>st</strong>ate changes occur.<br />

Chapter 12 ends by describing how Smalltalk classes and objects are able to handle <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

messages, thus making it possible to use Smalltalk’s class library to be used in a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

application.<br />

In chapter 13 we defined how a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> object can be translated to Smalltalk. This mapping<br />

is used by the compiler when it generates Smalltalk code from <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> source code.<br />

Additionally, we described how we can detect whether a method is a normal or an early<br />

returning method.<br />

Finally, chapter 14 outlines the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> programming environment which we have<br />

implemented. The environment is composed of the user interface that allows the user to<br />

edit, compile and execute a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> application, the compiler that translates <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> source<br />

code to Smalltalk according to the mapping defined in chapter 13, and a kernel for runtime<br />

support. The kernel contains the various classes necessary to execute a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

application, and additionally, a preemptive process scheduler that prevents Smalltalk’s<br />

non-preemptive processes to monopolize the Smalltalk Processor.<br />

Chapter 16: Conclusions


16.2 Conclusions<br />

In this thesis we have presented the definition and an implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

language. <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> has been implemented in Smalltalk and consi<strong>st</strong>s of a programming<br />

environment, which allows the user to edit, compile and execute a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> application.<br />

The implementation provides the mo<strong>st</strong> intere<strong>st</strong>ing aspects of the composition filters object<br />

model. It provides the five major filters, which allows us to demon<strong>st</strong>rate the power of the<br />

composition filters object model. The filters included are the dispatch filter, the error filter,<br />

the send filter, the wait filter, and the meta filter. Further, the implementation provides<br />

concurrency and synchronization.<br />

The implementation, however, does not provide type checking, neither does it implement<br />

full scope rules. The real-time filter has been omitted and so are atomic transactions and<br />

database functionalities for associative object access.<br />

We have come up with a representation for messages and filters which allows an easy<br />

implementation of the filtering process. Filters are able to reflect on messages (sy<strong>st</strong>em<br />

level reflection), and applications can use a meta filter to reflect on the communication<br />

between objects (application level reflection). We introduced a new dereification method<br />

which allows an ACT to regain control on a reified message when it obtains a reply.<br />

Finally, we have evaluated the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language and the composition filters object model.<br />

We have proposed a number of improvements to the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language in general, and to the<br />

syntax and semantics of composition filters.<br />

16.3 Future work<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> has not reached its final <strong>st</strong>ate. Although we have e<strong>st</strong>ablished the feasibility of the<br />

composition filters object model and the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> implementation, much work remains. This<br />

work can be categorized in bug fixes, implementation refinements, language<br />

improvements, and implementation optimizations.<br />

Bugs and problems The implementation has the following bugs and problems that need to be fixed:<br />

Making the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

implementation<br />

complete<br />

Improvements to the<br />

language<br />

• The synchronization bug, which causes under certain conditions blocked messages to<br />

be re<strong>st</strong>arted while this is not allowed.<br />

• The signature matching problem, which can cause a message to be dispatched to an<br />

object (because it is in its signature), but this object is unable to dispatch it further<br />

because conditions of its filters prevent this.<br />

• Condition reevaluation not only when the <strong>st</strong>ate of the object manager changes, but<br />

when any <strong>st</strong>ate changes.<br />

A number of aspects of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong> language were not addressed by this thesis. To provide a<br />

full implementation of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>, it needs to be extended with:<br />

• Type checking, and additionally signature matching which considers type information.<br />

• Full scope rules which do not re<strong>st</strong>rict external objects to be global objects only.<br />

• Atomic transactions and database functionalities for associative object access.<br />

• Real-time filter and real-time scheduling.<br />

The evaluation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> language discovered the following extensions and<br />

improvements:<br />

• New filter syntax and semantics, including the sub<strong>st</strong>itution filter.<br />

• Extension of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> with block closures.<br />

• An exception handling mechanism which allows to respond to run-time errors.<br />

• Message dereification which allows a message to be aborted.<br />

Evaluation and Conclusions<br />

143


144<br />

Optimizations The performance of the implementation presented in this thesis can be enhanced by:<br />

• Caching the signature of an object.<br />

• Further optimizing the message filtering process.<br />

• A <strong>st</strong>ack-based implementation, to eliminate the creation of a message object each time<br />

a message is sent.<br />

Of this li<strong>st</strong>, optimizations, type checking, real-time aspects, atomic transactions and<br />

database functionalities are the mo<strong>st</strong> intere<strong>st</strong>ing topics for future research.<br />

Chapter 16: Conclusions


PART<br />

v Appendices<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong><br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language


146


APPENDIX<br />

A <<strong>st</strong>rong>Sina</<strong>st</strong>rong> Class Interfaces<br />

A.1 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

#NoDefaultObject;<br />

class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object interface<br />

comment<br />

‘This class implements default behaviour.’;<br />

methods<br />

//-----window access<br />

print(s : String) returns nil;<br />

// Print the argument on my window. When the window was not opened yet,<br />

// it will be opened.<br />

printLine(s: String) returns nil;<br />

// Print the argument on my window followed by a CR. When the window<br />

// was not opened yet, it will be opened.<br />

cr returns nil;<br />

// Print a newline character on my window. When the window was not<br />

// opened yet, it will be opened.<br />

tab returns nil;<br />

// Print a tab character on my window. When the window was not opened<br />

// yet, it will be opened.<br />

openWindow returns nil;<br />

// Open or reopen my window.<br />

//-----error generation<br />

error(errorString : String) returns nil;<br />

// Generate an error.<br />

// The argument will be displayed on my window. Then, the thread that<br />

// invoked this method will be aborted.<br />

//-----dialogs<br />

warn(warning : String) returns nil;<br />

// Display a warning message.<br />

// Opens a dialog window displaying the argument; this method finishes<br />

// when the user hits the ‘ok’ box or types cr in the window.<br />

reque<strong>st</strong>(prompt : String) returns String;<br />

// Reque<strong>st</strong> a String to be typed from the keyboard.<br />

// Opens a dialog window displaying the argument; the user then has to<br />

// enter a String until he types cr; this method then answers the String<br />

// entered by the user.<br />

//-----<strong>st</strong>ring conversion<br />

toString returns String;<br />

// Answer a String whose characters are a description of the server.<br />

//-----class membership<br />

class returns Class;<br />

// Answers the class of the server.<br />

//-----inspecting<br />

inspect returns server;<br />

// Create an Inspector window on the server in which the user can examine<br />

// the server’s variables.<br />

//-----te<strong>st</strong>ing<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> language<br />

147


148<br />

isNil returns Boolean;<br />

// Te<strong>st</strong>s if the server is the nil object: since this is not the case, this<br />

// method always returns false.<br />

notNil returns Boolean;<br />

// Te<strong>st</strong>s if the server is not the nil object: since this is not the case, this<br />

// method always returns true.<br />

//-----comparing<br />

equal(anObject : Any) returns Boolean;<br />

// Answer whether the server and the argument represent the same<br />

// object, that is, have the same value.<br />

unequal(anObject : Any) returns Boolean;<br />

// Answer whether the receiver and the argument do not represent<br />

// the same object.<br />

// This method implemented as<br />

// return server.equal(anObject).not<br />

same(anObject : Any) returns Boolean;<br />

// Answer true if the server and the argument, anObject, are the same<br />

// object (have the same object pointer) and false otherwise.<br />

different(anObject : Any) returns Boolean;<br />

// Answer true if the server and the argument, anObject, are not the<br />

// same object (have the same object pointer) and false otherwise.<br />

// This method implemented as<br />

// return server.same(anObject).not<br />

inputfilters<br />

myBehavior : Dispatch = {inner.*}<br />

end; // interface of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object<br />

A.2 ActiveMessage<br />

#NoDefaultObject;<br />

class ActiveMessage interface<br />

comment<br />

‘This class represents an active message, that is, a message that is executing.<br />

Attributes of an active message include:<br />

- selector<br />

- arguments<br />

- sender<br />

- server<br />

- receiver’;<br />

methods<br />

//-----accessing attributes<br />

sender returns Any;<br />

// Answers my sender object.<br />

server returns Any;<br />

// Answers my server object .<br />

receiver returns Any;<br />

// Answers my receiver object.<br />

selector returns String;<br />

// Answers my selector.<br />

numArgs returns SmallInteger;<br />

// Answers the number of my arguments.<br />

args returns Array;<br />

// Answers an array containing my arguments.<br />

argsAt(n : SmallInteger) returns Any;<br />

// Answers my n’th argument.<br />

//-----te<strong>st</strong>ing<br />

isRecursive returns Boolean;<br />

// Answers whether this message is a recursive message, i.e. a message<br />

// sent to self, server or sender.<br />

argsOfAtEqual(sel : String; i : SmallInteger; anObject : Any) returns Boolean;<br />

// Answer true if my selector is ‘sel’ and my i’th argument is equal to<br />

// ‘anObject’. This method is implemented as:<br />

// return self.selector = sel and self.argsAt(i) = anObject<br />

Appendix A: <<strong>st</strong>rong>Sina</<strong>st</strong>rong> Class Interfaces


isNil returns Boolean;<br />

// Te<strong>st</strong>s if the server is the nil object: since this is not the case, this<br />

// method always returns false.<br />

notNil returns Boolean;<br />

// Te<strong>st</strong>s if the server is not the nil object: since this is not the case, this<br />

// method always returns true.<br />

//-----comparing<br />

equal(anObject : Any) returns Boolean;.<br />

// Answer whether the receiver and the argument represent the same<br />

// object.<br />

unequal(anObject : Any) returns Boolean;<br />

// Answer whether the receiver and the argument do not represent<br />

// the same object.<br />

// This method implemented as<br />

// return not server.equal(anObject)<br />

same(anObject : Any) returns Boolean;<br />

// Answer true if the server and the argument, anObject, are the same<br />

// object (have the same object pointer) and false otherwise.<br />

different(anObject : Any) returns Boolean;<br />

// Answer true if the server and the argument, anObject, are not the<br />

// same object (have the same object pointer) and false otherwise.<br />

// This method implemented as<br />

// return not server.same(anObject)<br />

//-----class membership<br />

class returns Class;<br />

// Answers the class of the server.<br />

inputfilters<br />

myBehavior : Dispatch = {inner.*};<br />

end; // interface of class ActiveMessage<br />

A.3 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message<br />

#NoDefaultObject;<br />

class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message interface<br />

comment<br />

‘This class represents a reified message. It inherits the behavior from class<br />

ActiveMessage and adds behavior for changing the message’s attributes<br />

and for dereification’;<br />

internals<br />

activeMessage : ActiveMessage;<br />

methods<br />

//-----dereification<br />

continue returns nil;<br />

// Causes me to be (re)activated. Does not wait for my reply.<br />

fire returns nil;<br />

// Same as the method ’continue’: causes me to be (re)activated.<br />

// Does not wait for my reply.<br />

send returns Any;<br />

// Causes me to be (re)activated. Waits until I have received a reply.<br />

// Answers my reply.<br />

sendContinue returns Any;<br />

// Causes me to be (re)activated. Waits until I have received a reply.<br />

// Then, I will be reactivated a second time. Answers my reply.<br />

// In fact, the message expression<br />

// result := aMsg.sendContinue;<br />

// is equivalent to<br />

// result := aMsg.send; aMsg.continue;<br />

reply(anObject : Any) returns nil;<br />

// Returns anObject as the reply to the sender of myself.<br />

//-----copying<br />

copy returns <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message;<br />

// Answers a copy of myself, which has the same selector, server,<br />

// receiver and arguments as me, but who’s sender is undefined (nil).<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> language<br />

149


150<br />

//-----changing message attributes<br />

setSender(senderObject :Any) returns nil;<br />

// Changes my sender to be the argument, senderObject.<br />

setServer(serverObject : Any) returns nil;<br />

// Changes my server to be the argument, serverObject.<br />

setReceiver(receiverObject : Any) returns nil;<br />

// Changes my receiver to be the argument, receiverObject.<br />

setSelector(selector : String) returns nil;<br />

// Changes my selector to be the argument, selector.<br />

setArgs(args : Array) returns nil;<br />

// Changes my arguments to be the argument, args.<br />

argsAtPut(n : SmallInteger; anObject : Any) returns nil;<br />

// My n’th argument will become the argument, anObject.<br />

inputfilters<br />

myBehavior : Dispatch = {activeMessage.*, inner.*};<br />

end; // interface of class <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message<br />

A.4 ObjectManager<br />

#NoDefaultObject;<br />

class ObjectManager interface<br />

methods<br />

active returns SmallInteger;<br />

// Answers the number of active method invocations in the object .<br />

activeForMethod(selector : String) returns SmallInteger;<br />

// Answers the number of active invocations of the method given by<br />

// the argument .<br />

blockedReq returns SmallInteger;<br />

// Answers the number of messages that have been blocked by an<br />

// input wait filter.<br />

blockedInv returns SmallInteger;<br />

// Answers the number of messages that have been blocked by an<br />

// output wait filter<br />

inputfilters<br />

myBehavior : Dispatch = {inner.*};<br />

end; // interface of class ObjectManager<br />

Appendix A: <<strong>st</strong>rong>Sina</<strong>st</strong>rong> Class Interfaces


APPENDIX<br />

B Using Smalltalk<br />

classes in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

B.1 <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> variable declaration using a Smalltalk class<br />

A variable v that is declared with the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> variable declaration v : C; will have an initial<br />

value (an object) assigned to it. This initial value will be an in<strong>st</strong>ance of the class C.<br />

Table B-1 li<strong>st</strong>s the initial values for some Smalltalk classes.When the class C is not li<strong>st</strong>ed<br />

in this table and C is a Smalltalk class, it will be initialized according to table B-2.<br />

TABLE B-1 Initial value of the variable v in the variable declaration v : C; a .<br />

Class C Initial value of v Class of v<br />

Number 0 SmallInteger<br />

Fraction 0/1 Fraction<br />

Integer 0 LargePositiveInteger<br />

LargeNegativeInteger 0 LargePositiveInteger<br />

LargePositiveInteger 0 LargePositiveInteger<br />

SmallInteger 0 SmallInteger<br />

LimitedPrecisionReal 0 SmallInteger<br />

Double 0.0d Double<br />

Float 0.0 Float<br />

Point 0@0 Point<br />

Character Character<br />

value: 0<br />

Character<br />

Boolean false False<br />

True true True<br />

False false False<br />

UndefinedObject nil UndefinedObject<br />

a. Note, that sometimes the class of v is not C. This is because in<strong>st</strong>ances of subclasses of<br />

ArithmeticValue will be created and initialized with the Smalltalk message zero. These<br />

subclasses include Number, LimitedPrecisionReal, Double, Float,<br />

Fraction, Integer, SmallInteger, LargeNegativeInteger,<br />

LargePositiveInteger and Point.<br />

TABLE B-2 <<strong>st</strong>rong>Sina</<strong>st</strong>rong> variable declaration using a Smalltalk class C<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong> variable declaration Smalltalk equivalent<br />

v : C; v := C new.<br />

v : C(Expr); v := C new: Expr.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> language<br />

151


152<br />

TABLE B-2 <<strong>st</strong>rong>Sina</<strong>st</strong>rong> variable declaration using a Smalltalk class C<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong> variable declaration Smalltalk equivalent<br />

v : C(Expr1, Expr2, ..., ExprN); v := C new: Expr1 with: Expr2<br />

... with: ExprN.<br />

v : C keyw; v := C keyw.<br />

v : C keyw1:...keywN:(Expr1, ..., ExprN); v := C keyw1: Expr1 ... keywN:<br />

ExprN.<br />

Examples:<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong><br />

n : SmallInteger;<br />

point1 : Point;<br />

point2 : Point x:y:(260,435);<br />

arr1 : Array; // size not specified<br />

arr2 : Array(n+2); // initial size given<br />

arr3 : Array with:with:with:(3, ’ element’, ’array’); //initialized array<br />

arr4 : TypedArray(6,SmallInteger); // this class has not been defined<br />

today : Date today;<br />

circle : Circle center:radius:(point2, 50);<br />

Smalltalk<br />

n := 0;<br />

point1 := 0@0;<br />

point2 := Point x: 260 y: 435.<br />

arr1 := Array new.<br />

arr2 := Array new: n+2.<br />

arr3 := Array with: 3 with: ’element’ with: ’array’.<br />

arr4 := TypedArray new: 6 with: SmallInteger.<br />

today := Date today.<br />

circle := Circle center: point2 radius: 50.<br />

B.2 Smalltalk selectors<br />

Smalltalk provides three types of selectors<br />

• unary, consi<strong>st</strong>ing of alpanumeric characters only, eg. today;<br />

• binary, consi<strong>st</strong>ing of one or two non-alphanumeric characters, eg. +;<br />

• and keyword, consi<strong>st</strong>ing of a sequence of alphanumeric characters plus a<br />

colon, eg. center:radius:.<br />

In <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> , a selector is allowed to consi<strong>st</strong> of alphanumeric or colon characters<br />

only. Therefore, Smalltalk unary and keyword selectors can be used in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong><br />

unchanged, but binary selectors mu<strong>st</strong> be converted to an equivalent selector as<br />

li<strong>st</strong>ed in the center column of table B-3. Alternatively, you can use an operator<br />

expression with an operator shown in the right column.<br />

Appendix B: Using Smalltalk classes in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong>


TABLE B-3 Smalltalk binary selectors and their equivalents in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong><br />

For the Smalltalk selector Use the <<strong>st</strong>rong>Sina</<strong>st</strong>rong> selector<br />

arithmetic<br />

Or use an operator<br />

expression with the <<strong>st</strong>rong>Sina</<strong>st</strong>rong><br />

operator<br />

+ plus +<br />

- minus -<br />

* times *<br />

/ divide /<br />

// div div<br />

\\ mod mod<br />

negated negated<br />

logical<br />

-<br />

& and and<br />

| or or<br />

not not<br />

comparing<br />

not<br />

> greater ><br />

>= atlea<strong>st</strong> >=<br />

< less <<br />


154<br />

Appendix B: Using Smalltalk classes in <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong>


APPENDIX<br />

C <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> syntax<br />

definition<br />

This appendix contains the syntax definition of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> in a notation used by the scanner<br />

and parser generator tool T-gen [Graver92a][Graver92b]. It is comprised of a token class<br />

specification and a grammar specification.<br />

The token class specification is a sequence of token class definitions. A token class is<br />

defined by its token class terminal, a colon (:), a regular expression, an optional scanner<br />

directive between curly braces ({}), and a terminating semicolon (;).<br />

The grammar specification is a sequence of production rule specifications similar to those<br />

used by YACC [Johnson75]. A production rule consi<strong>st</strong>s of a nonterminal, called the lefthand<br />

side of the production, followed by a colon (:), one or more right-hand side<br />

specifications separated by vertical bars (|), and is terminated by a semicolon (;). A righthand<br />

side specification is a sequence of terminals and nonterminals, and is optionally<br />

followed parser directive between curly braces ({}). A terminal is either a token between<br />

single quotes (‘’), or a token class. The parser directive is a translation symbol, which is<br />

either a Smalltalk identifier or a message selector, and is used to con<strong>st</strong>ruct a parse tree node<br />

for its associated production rule.<br />

Parse trees building A parse tree consi<strong>st</strong> of nodes where each node is an in<strong>st</strong>ance of a (subclass of)<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ParseTreeNode. Each node can have zero or more child nodes. The parser directive of<br />

the right-hand side of a production rule specifies the node returned after the rule, and the<br />

rules of its associated nonterminals have been processed.<br />

There are two types of parser directives used toe specify the result node of a production<br />

rule. If the directive is a capitalized Smalltalk identifier then it is interpreted as a class<br />

name, typically a subclass of <<strong>st</strong>rong>Sina</<strong>st</strong>rong>ParseTreeNode. An in<strong>st</strong>ance of the corresponding class<br />

is created, with the nodes associated with the right-hand side nonterminals as children.<br />

The second form of parser directive represents a Smalltalk message selector. These can be<br />

one of the predefined message selector or a user-defined selector. The predefined selectors<br />

include nil, liftRightChild and liftRightChild. The nil directive associates nil (the empty node)<br />

with the left-hand side of the production rule. The liftLeftChild directive in<strong>st</strong>ructs the parse<br />

tree building process not to con<strong>st</strong>ruct a new node, but in<strong>st</strong>ead to return the node associated<br />

with the fir<strong>st</strong> nonterminal and the nodes of the following nonterminals as its children. The<br />

liftRightChild directive similarly returns the node associated with the right-mo<strong>st</strong><br />

nonterminal with the preceding nonterminal nodes as its children.<br />

User-defined parser directives (message selectors) require to accept the same number of<br />

arguments as there are nonterminals in the right-hand side of the corresponding production<br />

rule. A message with the designated selector, and the nodes associated with the right-hand<br />

side nonterminals as arguments, will be sent to the tree builder, an in<strong>st</strong>ance of class<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Builder. The result of the corresponding <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Builder method will be returned as result<br />

node of the associated production rule. In the grammar specification we have indicated<br />

between double quotes (“”) the class of the object which this method returns.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

155


Appendix C: <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> syntax definition<br />

C.1 Token class specification<br />

“---------------------------------------------<br />

Revision date: 3 June 1994<br />

---------------------------------------------<br />

Notes:<br />

- Use FSABasedScannerWithOneTokenLookahead in order to<br />

be able to di<strong>st</strong>inguish a floating point dot from a message dot<br />

Eg. 3.0.negated and 3.negated<br />

- Identifiers are not allowed to have _-characters in them.<br />

- 7 February 1994: added<br />

- 3 June 1994: added<br />

---------------------------------------------”<br />

<br />

: [A-Za-z][A-Za-z0-9]*<br />

;<br />

<br />

: ([A-Za-z][A-Za-z0-9]*\:)+<br />

;<br />

<br />

: \-?[0-9]+(<br />

((\.[0-9]+)([de][\+\-]?[0-9]+)?)<br />

| e[\+\-]?[0-9]+)?<br />

; “[0-9]+(\.[0-9]+)?(e[\+\-]?[0-9]+)?”<br />

<br />

: ‘(~[‘] | [\t\r\n] | ‘’)*’“Do not compactDoubleApo<strong>st</strong>rophes”<br />

“An empty <strong>st</strong>ring ‘’ would become a single qoute”<br />

“Compaction of double apo<strong>st</strong>rophes is done in”<br />

“the method <<strong>st</strong>rong>Sina</<strong>st</strong>rong>Builder>>as<<strong>st</strong>rong>Sina</<strong>st</strong>rong>String:.”<br />

;<br />

<br />

: $[\t\r\n\s-\~]<br />

;<br />

<br />

: [\s\t\r]+ {ignoreDelimiter}<br />

;<br />

<br />

: // (\t | [\s-\~])*[\r \n]{ignoreComment}<br />

;<br />

C.2 Grammar specification<br />

“---------------------------------------------<br />

This is the <<strong>st</strong>rong>Sina</<strong>st</strong>rong> grammar specification augmented with<br />

parser directives<br />

---------------------------------------------<br />

Revision date: 3 June 1994<br />

Grammar <strong>st</strong>atus: LALR(1)<br />

---------------------------------------------<br />

Notes:<br />

- The interface, implementation or method commenttext mu<strong>st</strong><br />

be placed between two ’-characters.<br />

---------------------------------------------”<br />

“----------------Program-------------------”<br />

sinaProgram<br />

: classDeclarations mainOPT<br />

{classDecls:main:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>ProgramNodeHolder”<br />

| main<br />

{main:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>ProgramNodeHolder”<br />

;<br />

classDeclarations<br />

: classDeclaration<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ClassDeclarations}<br />

| classDeclarations classDeclaration<br />

{liftLeftChild}<br />

;<br />

classDeclaration<br />

: classInterface classImplementation<br />

{interface:implementation:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>ClassNode”<br />

;<br />

“----------------Class interface-------------------”<br />

classInterface<br />

: classSwitches<br />

‘class’ className classParameters ‘interface’<br />

comment<br />

externalsPart<br />

internalsPart<br />

conditionDeclarationsPart<br />

methodDeclarationsPart<br />

inputfiltersPart<br />

outputfiltersPart<br />

‘end’ ‘;’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>InterfaceNode}<br />

;<br />

externalsPart<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectDeclarations}<br />

“i.e. an empty collection”<br />

156


On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

| ‘externals’ objectDeclarations<br />

;<br />

internalsPart<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectDeclarations}<br />

“i.e. an empty collection”<br />

| ‘internals’ objectDeclarations<br />

;<br />

conditionDeclarationsPart<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ConditionDeclarations}<br />

“i.e. an empty collection”<br />

| ‘conditions’ conditionDeclarations<br />

;<br />

methodDeclarationsPart<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>MethodDeclarations}<br />

“i.e. an empy collection”<br />

| ‘methods’ methodDeclarations<br />

;<br />

inputfiltersPart<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Filters}<br />

“i.e. an empy collection”<br />

| ‘inputfilters’ filterDeclarations<br />

;<br />

outputfiltersPart<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Filters}<br />

“i.e. an empy collection”<br />

| ‘outputfilters’ filterDeclarations<br />

;<br />

“----------------Class implementation-------------------”<br />

classImplementation<br />

: ‘class’ className ‘implementation’<br />

comment<br />

in<strong>st</strong>varsPart<br />

conditionsPart<br />

initialMethod<br />

methodsPart<br />

‘end’ ‘;’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ImplementationNode}<br />

;<br />

in<strong>st</strong>varsPart<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectDeclarations}<br />

“i.e. an empty collection”<br />

| ‘in<strong>st</strong>vars’ objectDeclarations<br />

;<br />

conditionsPart<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Conditions}<br />

“i.e. an empty collection”<br />

| ‘conditions’ conditionImplementations<br />

;<br />

initialMethod<br />

: “empty”<br />

{nil}<br />

| ‘initial’ methodBody ‘;’<br />

;<br />

methodsPart<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Methods}<br />

“i.e. an empty collection”<br />

| ‘methods’ methodImplementations<br />

;<br />

“----------------Main-------------------”<br />

mainOPT<br />

: “empty”<br />

{nil}<br />

| main<br />

;<br />

main<br />

: ‘main’<br />

comment<br />

externalsPart<br />

tempsPart<br />

‘begin’<br />

<strong>st</strong>atements<br />

‘end’<br />

{main:externals:temps:<strong>st</strong>atements:}<br />

;<br />

“----------------Classes-------------------”<br />

className<br />

: <br />

{asIdentifier:}<br />

;<br />

classParameters<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectDeclarations}<br />

“i.e. an empty collection”<br />

| ‘(‘ parameterObjectDeclarations ‘)’<br />

;<br />

157


Appendix C: <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> syntax definition<br />

“classDescriptions<br />

: classDescription<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ClassDescriptions}<br />

| classDescriptions ‘;’ classDescription<br />

{liftLeftChild}<br />

;”<br />

classDescription<br />

: className classCon<strong>st</strong>ructor classArguments<br />

{classDescription:con<strong>st</strong>ructor:arguments:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>ClassDescriptionNode”<br />

;<br />

classCon<strong>st</strong>ructor<br />

: “empty”<br />

{nil}<br />

| selector<br />

;<br />

classArguments<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Expressions}<br />

“i.e. empty collection”<br />

| ‘(‘ expressions ‘)’<br />

;<br />

“----------------Conditions-------------------”<br />

conditionName<br />

: <br />

{asIdentifier:}<br />

;<br />

conditionDeclarations<br />

: “conditionDeclaration ‘;’”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ConditionDeclarations}<br />

| conditionDeclarations conditionDeclaration ‘;’<br />

{liftLeftChild}<br />

;<br />

conditionDeclaration<br />

: conditionName associativeParameter<br />

{conditionDecl:parameter:}<br />

| objectName ‘.’ conditionName<br />

{object:conditionDecl:}<br />

;<br />

conditionImplementations<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Conditions}<br />

“i.e. an empty collection”<br />

| conditionImplementations conditionImplementation ‘;’<br />

{liftLeftChild}<br />

;<br />

conditionImplementation<br />

: conditionName conditionParameter methodBody<br />

{condition:parameters:body:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>ConditionImplementationNode”<br />

;<br />

conditionParameter<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectDeclarations}<br />

“i.e. an empty collection”<br />

| ‘(‘ singleObjectDeclaration ‘)’<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectDeclarations”<br />

;<br />

“----------------Filters-------------------”<br />

filterName<br />

: <br />

{asIdentifier:}<br />

;<br />

filterDeclarations<br />

: “filterDeclaration ‘;’”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Filters}<br />

| filterDeclarations filterDeclaration ‘;’<br />

{liftLeftChild}<br />

;<br />

filterDeclaration<br />

: filterName ‘:’ filterHandler ‘=’ ‘{‘ filterElements ‘}’<br />

{filter:handler:elements:}<br />

| objectName ‘.’ filterName<br />

{object:filter:}<br />

;<br />

filterHandler<br />

: <br />

{asIdentifier:}<br />

;<br />

filterElements<br />

: filterElement<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>FilterElements}<br />

| filterElements ‘,’ filterElement<br />

{liftLeftChild}<br />

;<br />

filterElement<br />

: messagePattern<br />

{messagePattern:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>FilterElementNode”<br />

| conditionSet filterOperator messagePatternSet<br />

{conditions:operator:messages:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>FilterElementNode”<br />

;<br />

filterOperator<br />

158


On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

: ‘=>’<br />

{enableOperator}<br />

| ‘~>’<br />

{exclusionOperator}<br />

;<br />

conditionSet<br />

: condition<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>FilterConditions}<br />

| ‘{‘ conditions ‘}’<br />

;<br />

conditions<br />

: condition<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>FilterConditions}<br />

| conditions ‘,’ condition<br />

{liftLeftChild}<br />

;<br />

condition<br />

: conditionName associativeParameter<br />

{condition:associativeParameter:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>FilterConditionNode”<br />

| ‘true’<br />

{conditionTrue}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>FilterConditionTrueNode”<br />

;<br />

associativeParameter<br />

: “empty”<br />

{nil}<br />

| ‘(‘ ‘#’ ‘)’<br />

{associativeParameter}<br />

“answers $#”<br />

;<br />

messagePatternSet<br />

: messagePattern<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessagePatterns}<br />

| ‘{‘ messagePatterns ‘}’<br />

;<br />

messagePatterns<br />

: messagePattern<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessagePatterns}<br />

| messagePatterns ‘,’ messagePattern<br />

{liftLeftChild}<br />

;<br />

messagePattern<br />

: sub<strong>st</strong>itutionPart<br />

{sub<strong>st</strong>itutionPart:}<br />

| ‘[‘ matchingPart ‘]’ sub<strong>st</strong>itutionPart<br />

{matchingPart:sub<strong>st</strong>itutionPart:}<br />

;<br />

matchingPart<br />

: messageSelector<br />

{tsWildCard:}<br />

| objectName ‘.’ messageSelector<br />

{tsObject:selector:}<br />

| ‘*’ ‘.’ messageSelector<br />

{tsWildCard:}<br />

| ‘self’ ‘.’ messageSelector<br />

{tsSelf:}<br />

;<br />

sub<strong>st</strong>itutionPart<br />

: messageSelector<br />

{tsWildCard:}<br />

| objectName ‘.’ messageSelector<br />

{tsObject:selector:}<br />

| ‘*’ ‘.’ messageSelector<br />

{tsWildCard:}<br />

| ‘#’ ‘.’ messageSelector<br />

{tsHash:}<br />

| ‘inner’ ‘.’ messageSelector<br />

{tsInner:}<br />

| ‘self’ ‘.’ messageSelector<br />

{tsSelf:}<br />

;<br />

messageSelector<br />

: selector<br />

| ‘*’<br />

{selectorWildcard}<br />

;<br />

“----------------Methods-------------------”<br />

methodName<br />

: <br />

{asIdentifier:}<br />

| ‘and’<br />

{methodNameAnd}<br />

| ‘or’<br />

{methodNameOr}<br />

| ‘not’<br />

{methodNameNot}<br />

| ‘div’<br />

{methodNameDiv}<br />

| ‘mod’<br />

{methodNameMod}<br />

| ‘class’<br />

{methodNameClass}<br />

| ‘sender’<br />

{methodNameSender}<br />

159


Appendix C: <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> syntax definition<br />

| ‘server’<br />

{methodNameServer}<br />

;<br />

methodDeclarations<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>MethodDeclarations}<br />

| methodDeclarations methodDeclaration ‘;’<br />

{liftLeftChild}<br />

;<br />

methodDeclaration<br />

: methodName methodParameters ‘returns’ methodReturnType<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>MethodDeclarationNode}<br />

;<br />

“methodParameterTypes<br />

:” “empty”<br />

“ {nil}<br />

| ‘(‘ classDescriptions ‘)’<br />

;”<br />

methodImplementations<br />

: “methodImplementation ‘;’”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Methods}<br />

| methodImplementations methodImplementation ‘;’<br />

{liftLeftChild}<br />

;<br />

methodImplementation<br />

: methodHeader methodBody<br />

{liftLeftChild}<br />

;<br />

methodHeader<br />

: methodName methodParameters methodReturnTypeOPT<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>MethodNode}<br />

;<br />

methodParameters<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectDeclarations}<br />

“i.e. an empty collection”<br />

| ‘(‘ parameterObjectDeclarations ‘)’<br />

;<br />

methodReturnTypeOPT<br />

: “empty”<br />

{nil}<br />

| ‘returns’ methodReturnType<br />

;<br />

methodReturnType<br />

: ‘nil’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>NilNode}<br />

| classDescription<br />

;<br />

methodBody<br />

: comment<br />

tempsPart<br />

‘begin’<br />

<strong>st</strong>atements<br />

‘end’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>BodyNode}<br />

;<br />

tempsPart<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectDeclarations}<br />

“i.e. an empty collection”<br />

| ‘temps’ objectDeclarations<br />

;<br />

“----------------Statements-------------------”<br />

<strong>st</strong>atements<br />

: <strong>st</strong>atement<br />

{<strong>st</strong>atement:}<br />

| <strong>st</strong>atements ‘;’ <strong>st</strong>atement<br />

{<strong>st</strong>atements:<strong>st</strong>atement:}<br />

;<br />

<strong>st</strong>atement<br />

: “empty”<br />

{nil}<br />

| expression<br />

| assignment<br />

| returnExpression<br />

| conditionalStatement<br />

| whileStatement<br />

| forStatement<br />

;<br />

assignment<br />

: objectName ‘:=’ expression<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>AssignmentNode}<br />

;<br />

returnExpression<br />

: ‘return’<br />

{returnExpression}<br />

| ‘return’ expression<br />

{returnExpression:}<br />

;<br />

conditionalStatement<br />

: ‘if’ expression ‘then’ <strong>st</strong>atements elsePartOPT ‘end’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ConditionalNode}<br />

;<br />

elsePartOPT<br />

: “empty”<br />

160


On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

{nil}<br />

| ‘else’ <strong>st</strong>atements<br />

;<br />

whileStatement<br />

: ‘while’ expression<br />

‘begin’<br />

<strong>st</strong>atements<br />

‘end’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>WhileNode}<br />

;<br />

forStatement<br />

: ‘for’ objectName ‘:=’ expression ‘to’ expression forStep<br />

‘begin’<br />

<strong>st</strong>atements<br />

‘end’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ForNode}<br />

;<br />

forStep<br />

: “empty”<br />

{nil}<br />

| ‘by’ expression<br />

;<br />

“----------------Expressions-------------------”<br />

expressions<br />

: expression<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Expressions}<br />

| expressions ‘,’ expression<br />

{liftLeftChild}<br />

;<br />

expression<br />

: conjunction<br />

;<br />

conjunction<br />

: disjunction<br />

| conjunction ‘or’ disjunction<br />

{receiverOr:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

;<br />

disjunction<br />

: equality<br />

| disjunction ‘and’ equality<br />

{receiverAnd:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

;<br />

equality<br />

: relational<br />

| relational ‘=’ relational<br />

{receiverEqual:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

| relational ‘!=’ relational<br />

{receiverUnequal:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

| relational ‘==’ relational<br />

{receiverSame:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

| relational ‘=!=’ relational<br />

{receiverDifferent:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

;<br />

relational<br />

: arithmetic<br />

| arithmetic ‘=’ arithmetic<br />

{receiverAtlea<strong>st</strong>:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

;<br />

arithmetic<br />

: term<br />

| arithmetic ‘+’ term<br />

{receiverAdd:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

| arithmetic ‘-’ term<br />

{receiverSubtract:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

;<br />

term<br />

: factor<br />

| term ‘*’ factor<br />

{receiverTimes:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

| term ‘/’ factor<br />

{receiverDivide:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

| term ‘div’ factor<br />

{receiverDiv:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

| term ‘mod’ factor<br />

161


Appendix C: <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> syntax definition<br />

{receiverMod:arg:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

;<br />

factor<br />

: operand<br />

| ‘not’ operand<br />

{receiverNot:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

| ‘-’ operand<br />

{receiverNegated:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

;<br />

operand<br />

: object<br />

| objectManager ‘.’ message<br />

{manager:message:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>ManagerMessageSendNode”<br />

| ‘inner’ ‘.’ message<br />

{innerMessage:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>InnerMessageSendNode”<br />

| operand ‘.’ message<br />

{receiver:message:}<br />

“a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode”<br />

| ‘(‘ expression ‘)’<br />

{enclosedExpression:}<br />

;<br />

“----------------Objects-------------------”<br />

objectName<br />

: <br />

{asIdentifier:}<br />

;<br />

objectNames<br />

: objectName<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectNames}<br />

| objectNames ‘,’ objectName<br />

{liftLeftChild}<br />

;<br />

objectDeclarations<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectDeclarations}<br />

“i.e. an empty collection”<br />

| objectDeclarations objectDeclaration ‘;’<br />

{objectDeclarations:objectDeclaration:}<br />

;<br />

parameterObjectDeclarations<br />

: objectDeclaration<br />

| parameterObjectDeclarations ‘;’ objectDeclaration<br />

{objectDeclarations:objectDeclaration:}<br />

;<br />

objectDeclaration<br />

: objectNames ‘:’ classDescription<br />

{flattenDeclaration:type:}<br />

;<br />

singleObjectDeclaration<br />

: objectName ‘:’ classDescription<br />

{singleDeclaration:type:}<br />

;<br />

“objects<br />

: object ‘;’<br />

{OrderedChildren}<br />

| objects object ‘;’<br />

{liftLeftChild}<br />

;”<br />

object<br />

: objectName<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ObjectNode}<br />

| ‘nil’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>NilNode}<br />

| ‘true’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>TrueNode}<br />

| ‘false’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>FalseNode}<br />

| ‘self’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>SelfNode}<br />

| ‘server’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ServerNode}<br />

| ‘sender’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>SenderNode}<br />

| ‘message’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageNode}<br />

| <br />

{as<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Char:}<br />

“Remove the leading $-character”<br />

“Answers a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>CharNode”<br />

| <br />

{as<<strong>st</strong>rong>Sina</<strong>st</strong>rong>String:}<br />

“Remove the enclosing quotes”<br />

“Answers a <<strong>st</strong>rong>Sina</<strong>st</strong>rong>StringNode”<br />

| <br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>NumberNode}<br />

;<br />

objectManager<br />

: ‘^’ ‘self’<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ManagerSelfNode}<br />

| ‘^’ ‘server’<br />

162


On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

;<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>ManagerServerNode}<br />

“----------------Messages-------------------”<br />

message<br />

: selector messageArguments<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>MessageSendNode}<br />

;<br />

selector<br />

: <br />

{asSelector:}<br />

| <br />

{asSelector:}<br />

| ‘class’<br />

{selectorClass}<br />

| ‘server’<br />

{selectorServer}<br />

| ‘sender’<br />

{selectorSender}<br />

| ‘and’<br />

{selectorAnd}<br />

| ‘or’<br />

{selectorOr}<br />

| ‘not’<br />

{selectorNot}<br />

| ‘div’<br />

{selectorDiv}<br />

| ‘mod’<br />

{selectorMod}<br />

;<br />

messageArguments<br />

: “empty”<br />

{<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Expressions}<br />

“i.e. empty collection”<br />

| ‘(‘ expressions ‘)’<br />

;<br />

“----------------Miscellaneous-------------------”<br />

comment<br />

: “empty”<br />

{nil}<br />

| ‘comment’ commentText ‘;’<br />

;<br />

commentText<br />

: <br />

{sinaComment:}<br />

;<br />

classSwitches<br />

: “empty”<br />

{OrderedChildren}<br />

| classSwitches classSwitch<br />

{liftLeftChild}<br />

;<br />

classSwitch<br />

: ‘#’ switch switchParameters ‘;’<br />

{liftRightChild}<br />

;<br />

switch<br />

: <br />

{asIdentifier:}<br />

;<br />

switchParameters<br />

: “empty”<br />

{OrderedChildren}<br />

| switchParameters switchParameter<br />

{liftLeftChild}<br />

;<br />

switchParameter<br />

: <br />

{asString:}<br />

| <br />

{asIdentifier:}<br />

;<br />

163


164<br />

Appendix C: <<strong>st</strong>rong>Sina</<strong>st</strong>rong>⁄<strong>st</strong> syntax definition


APPENDIX<br />

D Conversion<br />

algorithm<br />

D.1 Introduction<br />

When a filter filters a message, the filter has to decide whether to accept or to reject the<br />

message. If the message is accepted by the filter, the accept action of the filter will be<br />

carried out. In the opposite case, if the message is rejected, the filter’s reject action will be<br />

carried out. The decision whether to accept or reject a message is called the accept te<strong>st</strong> of a<br />

filter.<br />

The accept te<strong>st</strong> The accept te<strong>st</strong> decides if a filter has to accept or to reject a message. The filter initializer<br />

of the filter defines which messages the filter accepts. Other messages thus are rejected.<br />

The accept te<strong>st</strong> is comprised of a number of sub te<strong>st</strong>s:<br />

• selector matching: the selector of the message mu<strong>st</strong> match with one specified in the<br />

filter initializer;<br />

• receiver matching: for a message pattern [μ]σ that consi<strong>st</strong>s both of a matching part μ<br />

and a sub<strong>st</strong>itution part σ, and that is not the pattern of an exclusion element, the target<br />

of the message mu<strong>st</strong> match with the target of the matching part μ;<br />

• signature matching: for a message pattern σ that consi<strong>st</strong>s only of a sub<strong>st</strong>itution part, or<br />

a message pattern [μ]σ in an exclusion element —of which the matching part μ is<br />

ignored—, the message mu<strong>st</strong> be included in the signature of the target of σ;<br />

• condition evaluation<br />

• yielding a sub<strong>st</strong>itution target and/or selector<br />

When a message is evaluated by a filter to detect if the filter has to accept or to reject the<br />

message, the filter has to evaluate the conditions that a relevant for the message. The filter<br />

initializer, the part between the curly braces in the filter declaration, specifies the<br />

conditions and which message targets and selectors it accepts. The filter initializer does not<br />

specify, though, which conditions have to be evaluated for one particular message selector<br />

seperately. This would be very convenient, for in<strong>st</strong>ance, when a message has been blocked<br />

by a wait filter, to reevaluate only those conditions that are relevant for the blocked<br />

message in order to see if it can be unblocked.<br />

This appendix presents an algorithm that converts a filter initializer into a selectorcondition<br />

dictionary. Such a dictionary holds for a particular selector, an entry that<br />

contains all the conditions to be evaluated for that selector. When a filter has to decide if a<br />

message mu<strong>st</strong> be accepted or rejected, it can select from the dictionary the entry for the<br />

message’s selector and evaluate them. If they evaluate to true, the message will be<br />

accepted, and otherwise it will be rejected.<br />

In the following subsection we will informally describe which conditions a filter has to<br />

evaluate if a message m with a certain selector passes the filter. In section D.3 we formally<br />

define the filter initializer, the selector-condition dictionary and the components that can be<br />

found in them. In section D.4 we present the algorithm that converts a filter initializer to a<br />

selector-condition dictionary.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> language<br />

165


166<br />

An exclusion filter<br />

element<br />

D.2 A closer look at the filter initializer<br />

We fir<strong>st</strong> describe informally which conditions have to be evaluated if a message m with a<br />

certain selector passes the filter. Consider, for example, a filter which has the following<br />

initializer:<br />

{c1=>[a.put]b.mput, {c2, c3}=>a.*, c4~>{*.get, c.*, d.*}}<br />

A message m with a selector put is accepted by the filter if it is accepted by either<br />

filterelement. This is the case if (1) m’s receiver is the object a and the condition c1 is true,<br />

or (2) if put is in the signature of a and either of the conditions c2 or c3 is true, or (3) if put<br />

is neither in c’s signature nor in d’s signature, and condition c4 is true. In case (1), a<br />

sub<strong>st</strong>itution target object b and selector mput is used for accept action of the message. In<br />

the latter two cases no sub<strong>st</strong>itution is returned.<br />

The conditions to be evaluated for a message with selector put can be written down into<br />

one condition which also <strong>st</strong>ates any sub<strong>st</strong>itutions that will be returned:<br />

(rcv(m)=a∧ c1:b.mput)<br />

∨(put∈sig(a)∧ (c2 ∨ c3):a.⊥)<br />

∨(¬( put∈sig(c) ∨ put∈sig(d)) )∧ c4:⊥)<br />

In this, the ¬ denotes the logical not, the ∨ the non-evaluating logical or, and the ∧ the<br />

non-evaluating logical and 1 . The sub<strong>st</strong>itutions that are returned are <strong>st</strong>ated after the colon,<br />

with ⊥ denoting that no sub<strong>st</strong>itution is returned.<br />

A message m with selector get is accepted if:<br />

(get∈sig(a)∧ (c2 ∨ c3):⊥)<br />

∨(¬( get∈sig(*) ∨ get∈sig(c)) ∨ get∈sig(d)))∧ c4:⊥)<br />

Since the selector get is always in the signature of any object (get∈sig(*)≡true), the la<strong>st</strong><br />

line will never be able to accept the message (because ¬(true ∨…∨…)≡false and so<br />

false∧c4≡false). The conditions to be be evaluated for a message with selector get can<br />

therefore be reduced to (get∈sig(a) ∧ (c2 ∨ c3): ⊥).<br />

A message m with any selector except put or get will be accepted if<br />

(sel(m)∈sig(a)∧ (c2 ∨ c3):⊥)<br />

∨(¬( sel(m)∈sig(c) ∨ sel(m)∈sig(d)) )∧ c4:⊥)<br />

From the previous, we can see that for the acceptance of a message by a filter, based on the<br />

selector of the message, the following conditions have to be evaluated:<br />

• a receiver or signature matching condition: the receiver of the message has to be a<br />

certain target object, or, the selector of the message has to be in the signature of a<br />

certain object.<br />

• certain combinations of conditions as <strong>st</strong>ated in the filter initializer; c1, c2, c3 and c4 in<br />

the initializer above.<br />

Consider a filter element {c1, c2}~>{a.get, b.*, *.put}. A message with a selector get will be<br />

accepted by this filter element when either of the conditions c1 or c2 evaluates to true and<br />

when this message is not accepted by the pattern set (since the exclusion operator ~><br />

preceeds the message pattern set). The message with selector get will be accepted by the<br />

pattern set if get ∈ sig(a) or get ∈ sig(b) 2 . Hence, a message with selector get will be<br />

accepted by this filter element when ¬(get ∈ sig(a) ∨ get ∈ sig(b)) ∧ (c1 ∨ c2). A same<br />

proposition can be derived for a message with selector put. It will be accepted by the filter<br />

1. A ∧ B will be evaluated as: if value of A is false then return false else return the value of B.<br />

A ∨ B will be evaluated as: if value of A is true then return true else return the value of B.<br />

Appendix D: Conversion algorithm


element when ¬(put ∈ sig(b) ∨ put ∈ sig(*)) ∧ (c1 ∨ c2). Since put is always in the<br />

signature of every object (put ∈ sig(*)≡true), this message will never be accepted by this<br />

filter element, regardless of the values of the conditions c1 and c2. A message m with any<br />

other selector than put or get will be accepted by the message pattern set if sel(m) ∈ sig(b),<br />

and therefore, it will be accepted by the filter element if ¬(sel(m) ∈ sig(b)) ∧ (c1 ∨ c2).<br />

From this, we can see that if a selector has been mentioned in the message pattern set of an<br />

exclusion filter element, then the accept conditions to be evaluated for one selector are<br />

comprised of the condition(s) of the filterelement and a logically negated conjunction —an<br />

or-ed combination— of signature conditions:<br />

¬(sel(m) ∈ sig(t 1 ) ∨…∨sel(m) ∈ sig(t n )) ∧ (c 1 ∨…∨c c ). If the selector has not been<br />

mentioned in the pattern set, the accept conditions consi<strong>st</strong> only of the condition(s) of the<br />

exclusion filter element.<br />

In the following section, we define an element containing a receiver or signature matching<br />

condition, a number of ordinary conditions and possibly returning a sub<strong>st</strong>itution target and<br />

selector as a condition-sub<strong>st</strong>itution element (f ∧ C: τ). For a message with a particular<br />

selector, a number of such condition-sub<strong>st</strong>itution elements have to be evalated until the<br />

fir<strong>st</strong> evaluates to true or all evaluate to false. In the latter case, the message will be rejected<br />

by the filter, whereas in the fir<strong>st</strong> case it will be accepted and the sub<strong>st</strong>itution τ of the fir<strong>st</strong><br />

element that evaluated to true will be used by the filter to change the message accordingly.<br />

D.3 Definitions<br />

The following three definitions describe a filter initializer and the components that can be<br />

found in it. The syntax of <<strong>st</strong>rong>Sina</<strong>st</strong>rong> allows you to omit parts of a filter element, and to declare<br />

ju<strong>st</strong> a single or a set of conditions and message patterns. In the definition of a filter<br />

element, though, we allow only a set of conditions on the left hand side of the enable or<br />

exclusion operator, and only a set of message patterns on the right hand side. However, a<br />

filter initializer can be easily rewritten to acommodate this requirement. For example, the<br />

following filter initializer<br />

{get, c1=>put, {c2, c3}=>[get2]inner.extract2}<br />

can be equivalently written as<br />

{ {true}=>{*.get}, {c1}=>{*.put}, {c2, c3}=>{[*.get2]inner.extract2} }<br />

In this form, each filter element has on the left hand side and on the right hand side of the<br />

=> operator a set of conditions and message patterns, respectively.<br />

DEFINITION D-1 Message pattern<br />

A message pattern is a tuple μσ, where<br />

μ denotes the matching part;<br />

σ denotes the sub<strong>st</strong>itution part.<br />

When no matching part μ is specified in the filter initializer, then μ is undefined: μ = ⊥.<br />

Both the sub<strong>st</strong>itution part and the matching part of a message pattern have two<br />

components: the target and the selector. They will be denoted as tar(μ), tar(σ), sel(μ) and<br />

sel(σ), respectively. For μ=⊥, the target and selector are undefined: tar(⊥) = sel(⊥) =⊥.<br />

DEFINITION D-2 Filter element<br />

A filter element is a triple CωΠ, where<br />

C is an ordered set of q conditions: C=[c 1 ,c 2 , …, c q ];<br />

2. For the moment, we consider only the selector of the message matches the signature of an object.<br />

The number and the types of arguments of the message should ofcourse also be regarded when<br />

we verify that the message matches the signature of the object.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> language<br />

167


168<br />

ω is either the enable operator => or the exclusion operator ~>;<br />

Π is an ordered set of m message patterns: Π =[μ 1 σ 1 , μ 2 σ 2 , …, μ m σ m ].<br />

DEFINITION D-3 Filter initializer<br />

A filter initializer FI = [C 1 ω 1 Π 1 , …, C n ω n Π n ] is an ordered set of n filter elements C i ω i Π i .<br />

As an example, the filter initializer { {empty, partial}=>{arr.put}, {partial}=>{inner.get},<br />

{full}=>{[self.get]*.*} }<br />

contains three filter elements C 1 ω 1 Π 1 , C 2 ω 2 Π 2 , C 3 ω 3 Π 3 , where<br />

C 1 = [empty, partial];<br />

C 2 = [partial];<br />

C 3 = [full];<br />

ω 1 = ω 2 = ω 3 = ‘=>’;<br />

Π 1 = [μ 1 σ 1 ], with μ 1 = ⊥, tar(σ 1 )=arr and sel(σ 1 )=put;<br />

Π 2 = [μ 2 σ 2 ], with μ 2 = ⊥, tar(σ 2 )=inner and sel(σ 2 )=get;<br />

Π 3 = [μ 3 σ 3 ], with tar(μ 3 )=self, sel(μ 3 )=get, tar(σ 3 )=* and sel(σ 3 )=*.<br />

The following definitions define the selector-condition dictionary and its components. A<br />

sub<strong>st</strong>itution is the target and the selector to be applied to the message if it is accepted by<br />

the filter. The receiver-signature match function tries either to match the target of a<br />

message pattern with the receiver of the message (the match function r(t)), or to check if<br />

the selector of the message is included in the signature of a target object (the match<br />

function s(t)) or excluded from the signature of a number of target objects (the match<br />

function e(t 1 , …, t n )). The match function r(t) always yields true when the target t is the<br />

wildcard target ‘*’, since the receiver of the message always matches with this target.<br />

Similarly, the match function s(t) always yields true when the target t is the wildcard target<br />

‘*’, since the selector of the message is always included in the signature of any object.<br />

Because the selector of a message is never excluded from the signature of every possible<br />

object, the match function e(t 1 , …, t n ) yields false when any t i is the wildcard target ‘*’.<br />

DEFINITION D-4 Sub<strong>st</strong>itution<br />

A sub<strong>st</strong>itution τ has a target tar(τ) and a selector sel(τ). Either can be undefined which will<br />

be denoted as tar(τ)=⊥ or sel(τ)=⊥. When both are undefined, τ=⊥.<br />

DEFINITION D-5 Match function<br />

A match function f is one of the five functions<br />

f =<br />

r() t<br />

⎧<br />

⎪ s() t<br />

⎪<br />

⎨e(<br />

t1, …, tn) ⎪<br />

⎪ true<br />

⎩<br />

false<br />

where<br />

r(t) denotes the match function rcv(m) =t. When t=‘*’ then r(t) yields true;<br />

s(t) denotes the match function sel(m) ∈sig(t). When t=‘*’ then s(t) yields true;<br />

e(t1 , …, tn ) denotes the match function ¬(sel(m) ∈sig(t1 ) ∨…∨ sel(m) ∈sig(tn )).<br />

When any ti = ‘*’ then e(t, …, tn ) yields false.<br />

DEFINITION D-6 Condition-sub<strong>st</strong>ition element<br />

A condition-sub<strong>st</strong>itution element is a triple fCτ, where<br />

f is a receiver-signature match;<br />

C is an ordered set of conditions;<br />

τ is a sub<strong>st</strong>itution.<br />

We will denote a condition-sub<strong>st</strong>itution element more readable with<br />

(f ∧ C: τ)<br />

which is to be interpreted as “if the receiver-signature match function f is true and (then) if<br />

either condition in the condition set C is true, then the condition-sub<strong>st</strong>itution element<br />

Appendix D: Conversion algorithm


yields true and sub<strong>st</strong>itution τ will be returned. Otherwise the condition-sub<strong>st</strong>itution<br />

element yields false.”.<br />

DEFINITION D-7 Selector-condition dictionary<br />

A selector-condition dictionary SD={s 1 →S 1 , …, s k →S k } is a set of k tuples s i →S i ,<br />

where<br />

s i is a selector or the wildcard selector *;<br />

S i is an ordered set of p condition-sub<strong>st</strong>itution elements: S i =[f 1 C 1 τ 1 , …, f p C p τ p ].<br />

The wildcard selector denotes a default entry for a selector that does not match a selector<br />

s j ≠ ‘*’, j = 1, …, k, contained in SD. A tuple s i →S i <strong>st</strong>ates that for a selector s i the<br />

condition-sub<strong>st</strong>itution elements of S i will have to be evaluated. The filter will accept a<br />

message with selector s when one of the condition-sub<strong>st</strong>itution elements f i C i τ i of the entry<br />

s→[f 1 C 1 τ 1 , …, f p C p τ p ] evaluates true.<br />

D.4 The algorithm<br />

The algorithm presented below will create a selector-condition dictionary from a filter<br />

initializer. The details of the algorithm will be elucidated after the algorithm.<br />

ALGORITHM D-1 Converting a filter initializer to a selector condition dictionary<br />

input: a filter initializer FI = [C1ω1Π1 , …, CnωnΠn ] containing n filter elements. (1)<br />

output: a selector-condition dictionary SD. (2)<br />

begin (3)<br />

create SD with selectors from FI; (4)<br />

for all (CiωiΠi ∈FI from 1 to n) (5)<br />

do if ωi =‘=>’ (6)<br />

then add filterelement CiωiΠi enabled to SD (7)<br />

else add filterelement CiωiΠi excluded to SD (8)<br />

fi; (9)<br />

od; (10)<br />

return SD (11)<br />

end (12)<br />

(13)<br />

add filterelement CiωiΠi enabled to SD (14)<br />

begin // ωi =‘=>’ (15)<br />

for all (μjσj ∈Πi from 1 to m) (16)<br />

do if μj = ⊥ (17)<br />

then ς := sel(σj );f := sel(m) ∈ sig(tar(σj ));τ := tar(σj ).⊥ (18)<br />

else ς := sel(μj );f := rcv(m) = tar(μj );τ := σj (19)<br />

fi; (20)<br />

if ς = ‘*’ (21)<br />

then for all (s→S ∈SD) do add ( f ∧ Ci : τ ) to S od (22)<br />

else add ( f ∧ Ci : τ ) to S where ς→S ∈ SD (23)<br />

fi (24)<br />

od (25)<br />

end (26)<br />

(27)<br />

add filterelement CiωiΠi excluded to SD (28)<br />

begin // ωi =‘~>’ (29)<br />

selSet := ∪μσ∈Πi {sel(σ)}; // selSet = {ς1 , …, ςs } (30)<br />

for all (s→S ∈ SD) (31)<br />

do if s ∈ selSet ∨ ‘*’ ∈ selSet (32)<br />

then (33)<br />

tarSet := ∪ μσ∈Πi : (sel(σ) =s ∨ sel(σ) = ‘*’) [tar(σ)] ; // tarSet = [υ 1 , …, υ t ] (34)<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> language<br />

169


170<br />

f := ¬( sel(m) ∈ sig(υ1 ) ∨…∨ sel(m) ∈ sig(υt )) (35)<br />

else // s ∉ selSet ∧ ‘*’ ∉ selSet (36)<br />

f := true (37)<br />

fi; (38)<br />

add ( f ∧ Ci : ⊥ ) to S (39)<br />

od (40)<br />

end (41)<br />

(42)<br />

create SD with selectors from FI; (43)<br />

begin (44)<br />

SD := ∅; (45)<br />

for all (CiωiΠi ∈FI from 1 to n) (46)<br />

do for all (μjσj ∈Πi from 1 to m) (47)<br />

do if μj = ⊥ or ωi =‘~>’ (48)<br />

then SD := SD ∪ { sel(σj )→∅ } (49)<br />

else SD := SD ∪ { sel(μj )→∅ } (50)<br />

fi (51)<br />

od (52)<br />

od (53)<br />

end (54)<br />

(55)<br />

add fCτ to S=[f1C1τ1 , …, fpCpτp ] (56)<br />

begin (57)<br />

S:=[f1C1τ1 , …, fpCpτp , fCτ] (58)<br />

end (59)<br />

The algorithm <strong>st</strong>arts by creating a selector-condition dictionary with an entry for all the<br />

selectors mentioned in the filter initializer (lines 4 and 43-54). The selector of the<br />

sub<strong>st</strong>itution part σ j will be used, when the filterelement is an exclusion element —<br />

remember that the matching part of a message pattern μ j σ j in an exclusion element is<br />

ignored—, or when no matching part μ j is defined. Otherwise the selector of the matching<br />

part μ j is used for an entry in the dictionary. The algorithm then continues by adding every<br />

filterelement in the filterinitializer to the dictionary (lines 5-10). The algorithm has to<br />

di<strong>st</strong>inguish between an element with an enable operator (ω i =‘=>’) or an exclusion<br />

operator (ω i =‘~>’).<br />

A filterelement with an enable operator will be added to the dictionary in the subroutine<br />

add filterelement enabled to SD (lines 14-26). All messagepatterns μ j σ j in the message<br />

pattern set Π i will be treated seperately. When the matching part μ j is undifined, signature<br />

matching will be used with the match function s(t) that checks if the selector of the<br />

message is included in the signature of target of σ j . In this case, no sub<strong>st</strong>itution will be<br />

returned (line 18). Otherwise, receiver matching is used with the match function r(t) that<br />

checks if the receiver of the message the target of μ j . The sub<strong>st</strong>itution returned in this case<br />

is the subtitution part σ j of μ j σ j (line 19). The selector matched in the former case is the<br />

selector of the sub<strong>st</strong>itution part and the selector of the matching part μ j in the latter case. A<br />

condition-sub<strong>st</strong>itution element fCτ, with the previously determined match function and<br />

sub<strong>st</strong>itution and the conditions C i of the filterelement, will be added to the dictionary entry<br />

of the selector only (line 23), or, when the selector is the wildcard selector *, to all selector<br />

entries in the dictionary (line 22), since condition-sub<strong>st</strong>itution element applies to all<br />

selectors in that case.<br />

A filterelement with an exclusion operator will be handled by the subroutine add<br />

filterelement excluded to SD (lines 28-41). Fir<strong>st</strong>, a set selSet of selectors that are mentioned<br />

in the message pattern set is con<strong>st</strong>ructed (line 30). Then, we iterate over all the selectors s<br />

in the selector dictionary (lines 31-40) to add a condition-sub<strong>st</strong>itution element for each s.<br />

In case, the selector s was not mentioned in the message pattern set (s ∉ selSet, line 36),<br />

whether s will be accepted only depends on the conditions C i (line 34). In the opposite<br />

case, when s was mentioned in the message pattern set (s ∈ selSet), the match function f is<br />

Appendix D: Conversion algorithm


uilt (line 34) from the targets that are applicable for s —all μσ∈Π i with sel(σ)=s or<br />

sel(σ)=‘*’— which have been collected in the set tarSet in the same ordering as they<br />

appeared in Π i .<br />

Rewrite rules<br />

The algorithm creates a dictionary in which for every possible selector the conditions are<br />

contained. The dictionary contains <strong>st</strong>ill all the information that is also <strong>st</strong>ored in the filter<br />

initializer. The dictionary can be further simplified by using rewrite rules that discard<br />

unneccessary information.<br />

DEFINITION D-8 Rewrite rules for a selector condition dictionary<br />

(1) A match function s(t) denoting the function sel(m) ∈ sig(t), can be replaced by the<br />

match function true when t = ‘*’.<br />

(2) A match function r(t) denoting the function rcv(m) = t can be replaced by the match<br />

function true when t = ‘*’.<br />

(3) A match function e(t 1 , …, t n ) denoting the function<br />

¬(sel(m) ∈sig(t 1 ) ∨…∨ sel(m) ∈sig(t n )) can be replaced by the match function false<br />

if any t i = ‘*’, i = 1 … n.<br />

(4) A condition-sub<strong>st</strong>itution element f i C i τ i can be removed from the ordered set<br />

S=[f 1 C 1 τ 1 , …, f i C i τ i , …, f p C p τ p ], with s→S ∈SD, when f i is the match function false.<br />

(5) An ordered set of conditions C = [c 1 , …, c i , …, c n ] can be replaced by C = [c 1 , …, c i ],<br />

if c i is the condition true.<br />

(6) An ordered set of condition-sub<strong>st</strong>itution elements S=[f 1 C 1 τ 1 , …, f i C i τ i , …, f p C p τ p ],<br />

with s→S ∈SD, can be replaced by S=[f 1 C 1 τ 1 , …, f i C i τ i ] if the element f i C i τ i<br />

always accepts the selector s. That is if f i is the match function true and any<br />

c j ∈ C i =[c 1 , …, c n ] is the condition true.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> language<br />

171


172<br />

Appendix D: Conversion algorithm


References<br />

[Aksit88] Mehmet Aksit and Anand Tripathi. “Data ab<strong>st</strong>raction mechanisms in sina/<strong>st</strong>.” In<br />

[Meyrowitz88], pages 267–275, 1988.<br />

[Aksit89] Mehmet Aksit. On the Design of the Object-Oriented Language <<strong>st</strong>rong>Sina</<strong>st</strong>rong>. Ph.D. dissertation,<br />

University of <strong>Twente</strong>, Dept. of Computer Science, P.O. box 217, 7500 AE, Enschede, The<br />

Netherlands, 1989. ISBN 90-365-0250-0.<br />

[Aksit91] Mehmet Aksit, Jan-Willem Dijk<strong>st</strong>ra, and Anand Tripathi. “Atomic Delegations: Object-<br />

Oriented Transactions.” IEEE Software, pages 84–92, March 1991. IEEE Computer<br />

Society, 10622 Los Vaqueros Cir., PO Box 3014, Los Alamitos, CA 90720-1264, USA.<br />

ISSN 0740-7459.<br />

[Aksit92a] Mehmet Aksit and Lodewijk Bergmans. Ob<strong>st</strong>acles in object-oriented software<br />

development. In Andreas Paepcke, editor, OOPSLA ’92, Conference Proceedings,<br />

volume 27 of ACM SIGPLAN Notices, pages 341–358, October 1992. ISSN 0362-1340,<br />

ISBN 0-201-53372-3.<br />

[Aksit92b] Mehmet Aksit, Lodewijk Bergmans, and <<strong>st</strong>rong>Sina</<strong>st</strong>rong>n Vural. An object-oriented languagedatabase<br />

integration model: The composition-filters approach. In Ole Lehrmann Madsen,<br />

editor, ECOOP ’92, European Conference on Object-Oriented Programming, number 615<br />

in Lecture Notes in Computer Science, pages 372–395, Berlin Heidelberg, June/July 1992.<br />

European Conference on Object-Oriented Programming, Springer-Verlag. ISBN 0-387-<br />

55668-0 / ISBN 3-540-55668-0.<br />

[Aksit93] Mehmet Aksit, Ken Wakita, Jan Bosch, Lodewijk Bergmans, and Akinori Yonezawa.<br />

Ab<strong>st</strong>racting object interactions using composition filters. In Rachid Guerraoui, Oscar<br />

Nier<strong>st</strong>rasz, and Michel Riveill, editors, ECOOP ’93, Workshop on Object-Based<br />

Di<strong>st</strong>ributed Programming, number 791 in Lecture Notes in Computer Science, pages 152–<br />

184, Berlin Heidelberg, July 1993. European Conference on Object-Oriented<br />

Programming, Springer-Verlag. ISBN 0-387-57932-X / ISBN 3-540-57932-X.<br />

[Aksit94] Mehmet Aksit, Jan Bosch, William van der Sterren, and Lodewijk Bergmans. Real-time<br />

specification inheritance anomalies and real-time filters. In Mario Tokoro and Remo<br />

Pareschi, editors, ECOOP ’94, Object-Oriented Programming, number 821 in Lecture<br />

Notes in Computer Science, pages 386–407, Berlin Heidelberg, July 1994. European<br />

Conference on Object-Oriented Programming, Springer-Verlag. ISBN 0-387-58202-9 /<br />

ISBN 3-540-58202-9.<br />

[Aksit95] Mehmet Aksit and Lodewijk Bergmans. “Application Domains and Ob<strong>st</strong>acles in<br />

Conventional Object-Oriented Software Development.” Draft version. University of<br />

<strong>Twente</strong>, Dept. of Computer Science, P.O. box 217, 7500 AE, Enschede, The Netherlands,<br />

1995.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

173


174<br />

[Algra94] Egbert Algra. “Process programming and learning domains in object oriented hermeneutic<br />

software development.” M.Sc. thesis, University of <strong>Twente</strong>, Dept. of Computer Science,<br />

P.O. box 217, 7500 AE, Enschede, The Netherlands, June 1994.<br />

[Bergmans94a] Lodewijk Bergmans. Composing Concurrent Objects. Ph.D. dissertation, University of<br />

<strong>Twente</strong>, Dept. of Computer Science, P.O. box 217, 7500 AE, Enschede, The Netherlands,<br />

June 1994. ISBN 90-9007359-0.<br />

[Bergmans94b] Lodewijk M.J. Bergmans. The Composition-Filters Object Model. This paper was derived<br />

from Chapter 2 of [Bergmans94a]. University of <strong>Twente</strong>, PO box 217, 7500 AE Enschede,<br />

The Netherlands, June 1994.<br />

[vDijk95] Wietze van Dijk and John Mordhor<strong>st</strong>. “CFIST: Composition Filters in Smalltalk.” HIO<br />

Graduation thesis, July 1995.<br />

[Ellis90] Margaret A. Ellis and Bjarne Strou<strong>st</strong>rup. The Annotated C++ Reference Manual.<br />

Addison-Wesley Publishing Company, Reading, Massachusetts, 1990. ISBN 0-201-<br />

51459-1.<br />

[Ferber89] Jaques Ferber. “Computational Reflection in Class-based Object-Oriented Languages.” In<br />

[Meyrowitz89], pages 317–326, 1989.<br />

[Goldberg83] Adele Goldberg and David Robson. Smalltalk-80 : The Language And Its Implementation.<br />

Addison-Wesley Series in Computer Science. Addison-Wesley, Reading, MA, USA, 1983.<br />

ISBN 0-201-11371-6.<br />

[Goldberg89] Adele Goldberg and David Robson. Smalltalk-80: The Language. Addison-Wesley Series<br />

in Computer Science. Addison-Wesley Publishing Company, Reading, MA, USA,<br />

September 1989. ISBN 0-201-13688-0.<br />

[Graver92a] Ju<strong>st</strong>in O. Graver. “T-gen: a <strong>st</strong>ring-to-object translator generator.” Journal of Object-<br />

Oriented Programming, 5(5):35–42, September 1992. SIGS Publications, Inc., 588<br />

Broadway, Suite 604, New York, NY 10012, USA. ISSN 0896-8438.<br />

[Graver92b] Ju<strong>st</strong>in O. Graver. T-gen Version 2.1 User’s Guide, 1992. Included in the T-gen package<br />

which is available at ftp://<strong>st</strong>.cs.uiuc.edu/pub/<strong>st</strong>80_r41/T-gen2.1/, and at ftp://<br />

mushroom.cs.man.ac.uk/pub/goodies/uiuc/<strong>st</strong>80_r41/T-gen2.1/.<br />

[Johnson75] S.C. Johnson. “Yacc - yet another compiler compiler.” Computing Science Technical<br />

Report 32, AT&T Bell Laboratories, Murray Hill, New Jersey, USA, 1975.<br />

[Koopmans95] Piet S. Koopmans. <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> User’s Guide and Reference Manual. TRESE Project,<br />

Department of Computer Science, University of <strong>Twente</strong>, Enschede, The Netherlands,<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> version 3.00 edition, Augu<strong>st</strong> 1995.<br />

[Maes87] Pattie Maes. “Concepts and Experiments in Computational Reflection.” In [Meyrowitz87],<br />

pages 147–155, 1987.<br />

[Meyrowitz86] Norman Meyrowitz, editor. OOPSLA ’86 Conference Proceedings, volume 21 of<br />

SIGPLAN Notices, 11 We<strong>st</strong> 42nd Street, New York, New York 10036, USA, September<br />

1986. Association for Computing Machinery’s Special Intere<strong>st</strong> Group on Programming<br />

Languages (ACM/SIGPLAN), Association for Computing Machinery, Inc. ISBN 0-<br />

89791-204-7.<br />

[Meyrowitz87] Norman Meyrowitz, editor, OOPSLA ’87 Conference Proceedings, volume 22 of<br />

SIGPLAN Notices, 11 We<strong>st</strong> 42nd Street, New York, New York 10036, USA, December<br />

1987. Association for Computing Machinery’s Special Intere<strong>st</strong> Group on Programming<br />

Languages (ACM/SIGPLAN), Association for Computing Machinery, Inc. ISBN 0-<br />

89791-247-0.<br />

References


[Meyrowitz88] Norman Meyrowitz, editor. OOPSLA ’88, Conference Proceedings, volume 23 of<br />

SIGPLAN Notices, 11 We<strong>st</strong> 42nd Street, New York, NY 10036, USA, November 1988.<br />

Special Intere<strong>st</strong> Group on Programming Languages, Association for Computing<br />

Machinery, Association for Computing Machinery, Inc. ISBN 0-89791-284-5, ISSN 0362-<br />

1340.<br />

[Meyrowitz89] Norman Meyrowitz, editor. OOPSLA ’89, Conference Proceedings, volume 24 of<br />

SIGPLAN Notices, 11 We<strong>st</strong> 42nd Street, New York, NY 10036, USA, October 1989.<br />

Special Intere<strong>st</strong> Group on Programming Languages, Association for Computing<br />

Machinery, Association for Computing Machinery, Inc. ISBN 0-0201-52249-7, ISSN<br />

0362-1340.<br />

[Marcelloni95] Francesco Marcelloni and Mehmet Aksit. “Design and Implementation of the Object-<br />

Oriented Fuzzy-Logic Reasoning Framework.” Draft version, University of <strong>Twente</strong>,<br />

P.O.Box 217, 7500 AE Enschede, The Netherlands, 1995.<br />

[ParcPlace92a] ParcPlace Sy<strong>st</strong>ems, 999 E. Arques Ave., Sunnyvale, CA 94086–4593, USA.<br />

Objectworks\Smalltalk Release 4.1 User’s Guide, 1992.<br />

[ParcPlace92b] ParcPlace Sy<strong>st</strong>ems, 999 E. Arques Ave., Sunnyvale, CA 94086–4593, USA. VisualWorks<br />

Release 1.0 User’s Guide, 1992.<br />

[Rumbaugh91] James Rumbaugh, Michael Blaha, William Premerlani, Frederick Eddy, and William<br />

Lorensen. Object-Oriented modeling and design. Prentice-Hall International Inc.,<br />

Englewoods Cliffs, New Jersey 07632, 1991. ISBN 0-13-630054-5.<br />

[Tekinerdogan94] Bedir Tekinerdogan. “The design of an object-oriented framework for atomic<br />

transactions.” M.Sc. thesis, University of <strong>Twente</strong>, Dept. of Computer Science, P.O. box<br />

217, 7500 AE, Enschede, The Netherlands, March 1994.<br />

[Ungar87] David Ungar and Randall B. Smith. “Self: The Power of Simplicity.” In [Meyrowitz87] ,<br />

pages 227–242.<br />

[Vuij<strong>st</strong>94] Charles Vuij<strong>st</strong>. “Design of an Object-Oriented Framework for Image Algebra.” M.Sc.<br />

thesis, University of <strong>Twente</strong>, Dept. of Computer Science, P.O. box 217, 7500 AE,<br />

Enschede, The Netherlands, December 1994.<br />

[Wegner87] Peter Wegner. “Dimensions of object-based language design.” In [Meyrowitz87], pages<br />

168–182, 1987.<br />

[Wirfs-Brock90] Rebecca Wirfs-Brock, Brian Wilkerson, and Lauren Wiener. Designing Object-Oriented<br />

Software. Prentice Hall, Inc., Englewood Cliffs, New Jersey 07632, USA, 1990. ISBN 0-<br />

13-629825-7.<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

175


176<br />

References


Index<br />

#Category . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .41<br />

#DefaultObject . . . . . . . . . . . . . . . . . . . . . . . . . . .41<br />

#DefBehaviorFilter . . . . . . . . . . . . . . . . . . . . . . . .42<br />

#DefSyncFilter . . . . . . . . . . . . . . . . . . . . . . . . . . .41<br />

#NoDefaultObject. . . . . . . . . . . . . . . . . . . . . . . . .41<br />

#NoDefBehaviorFilter. . . . . . . . . . . . . . . . . . . . . .42<br />

#NoDefSyncFilter. . . . . . . . . . . . . . . . . . . . . . . . .41<br />

^self (pseudo variable). . . . . . . . . . . . . . . . . . . .30<br />

messages to ~ . . . . . . . . . . . . . . . . . . . . . . . .62<br />

see also object manager<br />

^server (pseudo variable) . . . . . . . . . . . . . . . . .30<br />

messages to ~ . . . . . . . . . . . . . . . . . . . . . . . .62<br />

see also object manager<br />

A<br />

ab<strong>st</strong>ract communication type . . . . . . . . . . . . . .73<br />

ACT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73<br />

active message . . . . . . . . . . . . . . . . . . . . . . .74, 77<br />

ActiveMessage (class) . . . . . . . . . . . . . . . .75, 148<br />

Any (type) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26<br />

assignment <strong>st</strong>atement . . . . . . . . . . . . . . . . . . . .28<br />

B<br />

behavior injection . . . . . . . . . . . . . . . . . . . . . . . .7<br />

C<br />

character literal . . . . . . . . . . . . . . . . . . . . . . . . .24<br />

class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .39<br />

~ parameter . . . . . . . . . . . . . . . . . . . . . . . . . .25<br />

~ switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . .40<br />

declaration. . . . . . . . . . . . . . . . . . . . . . . . . . .39<br />

implementation part . . . . . . . . . . . . . . . . . . .40<br />

in<strong>st</strong>ance of a ~. . . . . . . . . . . . . . . . . . . . . . . .43<br />

interface part . . . . . . . . . . . . . . . . . . . . . . . . .39<br />

comment. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23<br />

composition filters object model . . . . . . . . .6, 15<br />

concurrency . . . . . . . . . . . . . . . . . . . . . . . . .45, 76<br />

condition. . . . . . . . . . . . . . . . . . . . . . . . . . . .16, 57<br />

~ in filterinitializer . . . . . . . . . . . . . . . . . . . .64<br />

conditional <strong>st</strong>atement . . . . . . . . . . . . . . . . . . . .37<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

177<br />

continue (dereification method). . . . . . . . . 78, 79<br />

control flow. . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />

requirements . . . . . . . . . . . . . . . . . . . . . . . . 51<br />

~ for the conditional <strong>st</strong>atement. . . . . . . 52<br />

~ for the while and for <strong>st</strong>atement . . . . . 52<br />

control <strong>st</strong>ructure . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

conditional <strong>st</strong>atement . . . . . . . . . . . . . . . . . 37<br />

for <strong>st</strong>atement . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

while <strong>st</strong>atement . . . . . . . . . . . . . . . . . . . . . . 38<br />

D<br />

dereification . . . . . . . . . . . . . . . . . . . . . . . . 77, 78<br />

dispatch filter . . . . . . . . . . . . . . . . . .7, 69, 70, 108<br />

E<br />

early return . . . . . . . . . . . . . . . . . . . . . . . . . 51, 55<br />

error filter . . . . . . . . . . . . . . . . . . . . .7, 69, 70, 109<br />

exclusionelement . . . . . . . . . . . . . . . . . . . . . . . 64<br />

expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />

message expression. . . . . . . . . . . . . . . . . . . 32<br />

operator expression. . . . . . . . . . . . . . . . . . . 33<br />

external . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16, 25<br />

F<br />

false . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

filter<br />

~condition . . . . . . . . . . . . . . . . . . . . . . . . . . 64<br />

~element. . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

exclusionelement . . . . . . . . . . . . . . . . . . 64<br />

inclusionelement . . . . . . . . . . . . . . . . . . 64<br />

rewrite rules . . . . . . . . . . . . . . . . . . . . . . 65<br />

~handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69<br />

dispatch . . . . . . . . . . . . . . . . . . . 69, 70, 108<br />

error . . . . . . . . . . . . . . . . . . . . . . 69, 70, 109<br />

meta . . . . . . . . . . . . . . . . . . . . . . 69, 71, 109<br />

send . . . . . . . . . . . . . . . . . . . . . . 69, 70, 109<br />

wait . . . . . . . . . . . . . . . . . . . . . . 69, 70, 109<br />

~initializer . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

declaration . . . . . . . . . . . . . . . . . . . . . . . . . . 63


178<br />

dispatch ~ . . . . . . . . . . . . . . . . . . 7, 69, 70, 108<br />

error ~ . . . . . . . . . . . . . . . . . . . . . 7, 69, 70, 109<br />

input filters . . . . . . . . . . . . . . . . . . . . . . .16, 62<br />

local ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

messagepattern . . . . . . . . . . . . . . . . . . . . . . 64<br />

matchingpattern . . . . . . . . . . . . . . . . . . . 64<br />

signaturepattern . . . . . . . . . . . . . . . . . . . 64<br />

meta ~ . . . . . . . . . . . . . . . . . . . . . 7, 69, 71, 109<br />

output filters . . . . . . . . . . . . . . . . . . . . . .16, 62<br />

reused ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

send ~. . . . . . . . . . . . . . . . . . . . . . 7, 69, 70, 109<br />

wait ~ . . . . . . . . . . . . . . . . . . . . . . 7, 69, 70, 109<br />

fir<strong>st</strong>-class object . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

floating point literal. . . . . . . . . . . . . . . . . . . . . 24<br />

for <strong>st</strong>atement. . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

G<br />

global external . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

I<br />

implementation part . . . . . . . . . . . . . . . . . . . . 19<br />

inclusionelement . . . . . . . . . . . . . . . . . . . . . . . 64<br />

initial method . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

inner (pseudo variable) . . . . . . . . . . . . . . . . . . 30<br />

during method invocation . . . . . . . . . . . . . 55<br />

messages to ~ . . . . . . . . . . . . . . . . . . . . . . . 62<br />

input filters . . . . . . . . . . . . . . . . . . . . . . . . . .16, 62<br />

in<strong>st</strong>ance variable . . . . . . . . . . . . . . . . . . . . .16, 25<br />

integer literal . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

interface method . . . . . . . . . . . . . . . . . . . . . . . 45<br />

interface part . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

internal . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16, 25<br />

L<br />

literal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

character . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

floating point . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

integer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

number. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

<strong>st</strong>ring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

local variable . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

M<br />

main method . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

matchingpattern . . . . . . . . . . . . . . . . . . . . . . . . 64<br />

message<br />

active ~ . . . . . . . . . . . . . . . . . . . . . . . 74, 77, 97<br />

dereification. . . . . . . . . . . . . . . . . . . 77, 78, 112<br />

continue . . . . . . . . . . . . . . . . . . . . . . . .78, 79<br />

reply . . . . . . . . . . . . . . . . . . . . . . . . . . .79, 80<br />

send . . . . . . . . . . . . . . . . . . . . . . . . . . .79, 82<br />

Index<br />

filtering a ~. . . . . . . . . . . . . . . . . . . . . . 66, 101<br />

recursive ~ . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

reification . . . . . . . . . . . . . . . . . .73, 77, 77, 112<br />

reified ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />

sending a ~ . . . . . . . . . . . . . . . . . . . . . . . . . . 73<br />

message (pseudo variable) . . . . . . . . . . . . 30, 75<br />

during condition invocation. . . . . . . . . . . . 59<br />

during method invocation . . . . . . . . . . . . . 55<br />

messages to ~. . . . . . . . . . . . . . . . . . . . . . . . 62<br />

message expression . . . . . . . . . . . . . . . . . . . . . 32<br />

message representation . . . . . . . . . . . . . . . . . . 97<br />

messagepattern . . . . . . . . . . . . . . . . . . . . . . . . . 64<br />

matchingpattern. . . . . . . . . . . . . . . . . . . . . . 64<br />

signaturepattern . . . . . . . . . . . . . . . . . . . . . . 64<br />

meta filter . . . . . . . . . . . . . . . . . . . . .7, 69, 71, 109<br />

method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

~ invocation . . . . . . . . . . . . . . . . . . . . . 54, 109<br />

~ parameter . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

control flow in a ~ . . . . . . . . . . . . . . . . . . . . 50<br />

early return ~ . . . . . . . . . . . . . . . . . . . . 51, 111<br />

invocation of an ~ . . . . . . . . . . . . . . . . . 55<br />

initial ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

interface ~ . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

main ~. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

normal ~ . . . . . . . . . . . . . . . . . . . . . . . . 51, 111<br />

invocation of a ~ . . . . . . . . . . . . . . . . . . 55<br />

private ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

returning a value from a ~ . . . . . . . . . . . . . 49<br />

returntype . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

N<br />

nil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

normal return . . . . . . . . . . . . . . . . . . . . . . . 51, 55<br />

O<br />

object manager . . . . . . . . . . . . . . . . . . .30, 44, 116<br />

^self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

^server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

ObjectManager (class) . . . . . . . . . . . . . . . . 44, 150<br />

operator expression . . . . . . . . . . . . . . . . . . . . . 33<br />

output filters . . . . . . . . . . . . . . . . . . . . . . . . 16, 62<br />

owner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

P<br />

private method . . . . . . . . . . . . . . . . . . . . . . . . . 48


pseudo variable . . . . . . . . . . . . . . . . . . . . . . . . .29<br />

^self. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30<br />

^server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30<br />

inner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30<br />

message . . . . . . . . . . . . . . . . . . . . . . . . . .30, 75<br />

messages to ~ . . . . . . . . . . . . . . . . . . . . . . . .62<br />

self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30<br />

sender. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30<br />

server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30<br />

R<br />

reification . . . . . . . . . . . . . . . . . . . . . . . . . . .77, 77<br />

reified message . . . . . . . . . . . . . . . . . . . . . . . . .77<br />

reply<br />

(dereification method) . . . . . . . . . . . . . .79, 80<br />

(method return). . . . . . . . . . . . . . . . . . . . . . .50<br />

return<br />

early ~ . . . . . . . . . . . . . . . . . . . . . . . . . . .51, 55<br />

normal ~ . . . . . . . . . . . . . . . . . . . . . . . . .51, 55<br />

return <strong>st</strong>atement . . . . . . . . . . . . . . . . . . . . . . . . .50<br />

returntype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .45<br />

S<br />

self (pseudo variable) . . . . . . . . . . . . . . . . . . . .30<br />

during method invocation . . . . . . . . . . . . . .55<br />

messages to ~ . . . . . . . . . . . . . . . . . . . . . . . .62<br />

send (dereification method) . . . . . . . . . . . .79, 82<br />

send filter . . . . . . . . . . . . . . . . . . . . . 7, 69, 70, 109<br />

sender (pseudo variable). . . . . . . . . . . . . . . . . .30<br />

during method invocation . . . . . . . . . . . . . .55<br />

messages to ~ . . . . . . . . . . . . . . . . . . . . . . . .62<br />

server (pseudo variable) . . . . . . . . . . . . . . . . . .30<br />

during method invocation . . . . . . . . . . . . . .55<br />

messages to ~ . . . . . . . . . . . . . . . . . . . . . . . .62<br />

signature of an object . . . . . . . . . . . . . . . .68, 106<br />

signaturepattern . . . . . . . . . . . . . . . . . . . . . . . . .64<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Message (class). . . . . . . . . . . . . . . . . .86, 149<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Object (class) . . . . . . . . . . . . . . . . . . . .41, 147<br />

<<strong>st</strong>rong>Sina</<strong>st</strong>rong>Repository (global external). . . . . . 28, 29, 49<br />

<strong>st</strong>atement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .56<br />

assignment ~ . . . . . . . . . . . . . . . . . . . . . . . . .28<br />

conditional ~ . . . . . . . . . . . . . . . . . . . . . . . . .37<br />

for ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .37<br />

message expression . . . . . . . . . . . . . . . . . . .32<br />

operator expression . . . . . . . . . . . . . . . . . . .33<br />

return ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . .50<br />

while ~. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .38<br />

<strong>st</strong>ring literal . . . . . . . . . . . . . . . . . . . . . . . . . . . .24<br />

synchronization . . . . . . . . . . . . . . . . . . . . . . . .116<br />

T<br />

thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .74, 75<br />

TRESE project. . . . . . . . . . . . . . . . . . . . . . . . . . .3<br />

On the Definition and Implementation of the <<strong>st</strong>rong>Sina</<strong>st</strong>rong>/<strong>st</strong> Language<br />

179<br />

true . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

type<br />

~description . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

Any . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

method return~ . . . . . . . . . . . . . . . . . . . . . . 45<br />

V<br />

variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

assignment . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

class parameter . . . . . . . . . . . . . . . . . . . . . . 25<br />

declaration . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

external. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

global external. . . . . . . . . . . . . . . . . . . . . . . 28<br />

initial value . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

in<strong>st</strong>ance ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

internal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

local ~. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

method parameter . . . . . . . . . . . . . . . . . . . . 25<br />

typedescription . . . . . . . . . . . . . . . . . . . . . . 26<br />

W<br />

wait filter . . . . . . . . . . . . . . . . . . . . . .7, 69, 70, 109<br />

while <strong>st</strong>atement. . . . . . . . . . . . . . . . . . . . . . . . . 38

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!