Sina/st - trese - Universiteit Twente
Sina/st - trese - Universiteit Twente
Sina/st - trese - Universiteit Twente
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