language design rationale and semantic framework for
TRANSCRIPT
Language Design Rationale andSemantic Framework for ConcurrentObject-Oriented Programming
La Conception et la Description de la Sémantique
des Langages Concurrents à Objets
Michael Papathomas
Genève 1992
Language Design Rationale andSemantic Framework for ConcurrentObject-Oriented Programming
La Conception et la Description de la Sémantique
des Langages Concurrents à Objets
Michael Papathomas
Genève 1992
Michael Papathomas
L’application de l’approche de programmation par objets pour des applications concurrentes né-
cessite d’une part, des langages de programmation intégrant les concepts de la programmation
par objets à ceux de la programmation concurrente et d’autre part, afin de permettre leur réutili-
sation et évolution, une description précise du comportement des objets concurrents et une no-
tion formelle de comportement compatible.
Nous développons un cadre conceptuel, consistant en une typologie des choix de concep-
tion des langages et un ensemble de critères d’intégration de la programmation concurrente à la
programmation par objets, nous permettant d’évaluer les différentes combinaisons de choix de
conception. Puis, nous proposons une approche pour la description formelle de la sémantique
des langages concurrents à objets qui nous permet de représenter les différents choix de concep-
tion des langages et d’obtenir une notion formelle du comportement des objets concurrents.
Language Design Rationale and Semantic Framework for
Concurrent Object-Oriented Programming
La Conception et la Description de la Sémantique
des Langages Concurrents à Objets
UNIVERSITÉ DE GENÈVEDépartement d’Informatique
FACULTÉ DES SCIENCESProfesseur C.PELLEGRINI
Language Design Rationale andSemantic Framework for
Concurrent Object-Oriented Programming
THÈSE
Présentée à la Faculté des Sciences de l’Université de Genève
pour obtenir le grade de Docteur ès Sciences mention Informatique
par
Michael PAPATHOMAS
de
Athènes, Grèce
Thèse No 2522
Genève 1992
La Faculté des Sciences, sur le préavis de Messieurs C. PELLEGRINI, professeur ordinaire et
directeur de thèse (Département d’informatique), D. TSICHRITZIS, professeur ordinaire et co-
directeur de thèse (Faculté des Sciences économiques et sociales - Centre Universitaire d’Infor-
matique), A. YONEZAWA, professeur (Université de Tokyo) et O.M. NIERSTRASZ, docteur
(Faculté des Sciences économiques et sociales - Centre Universitaire d’Informatique), autorise
l’impression de la présente thèse, sans exprimer d’opinion sur les propositions qui y sont énon-
cées.
Genève, le 6 janvier 1992
Thèse No 2522
Le Doyen, Pierre BURI
© Michael Papathomas 1992. Tous droits réservés
Remerciements
Il y a un certain nombre de personnes qui ont joué un rôle important pour la réalisation de ce
travail et auxquelles j’aimerais exprimer ma gratitude.
Je remercie le Professeur D. Tsichritzis pour avoir suivi et soutenu ce travail depuis le dé-
but ainsi que pour sa confiance. Il m’a permis non seulement d’accomplir cette thèse mais aussi
d’élargir considérablement mes connaissances.
Je remercie le Professeur C. Pellegrini pour avoir accepter la direction de cette thèse et
avoir rendu possible ça réalisation.
Je remercie le Professeur A. Yonezawa pour m’avoir fait l’honneur de faire partie du jury
ainsi que pour son encouragement.
J’ai plusieurs raisons pour remercier le Docteur O.M. Nierstrasz. J’aimerais le remercier
plus particulièrement pour m’avoir fait connaître le calcul des processus, pour avoir lu et com-
menté plusieurs versions antérieures de cette thèse et pour avoir été toujours prêt à s’engager
dans des discussions stimulantes.
Je remercie L. Dami et J. Vitek pour leur encouragement qui a été inestimable ainsi que
pour leurs commentaires et suggestions qui m’ont permis d’améliorer considérablement la pré-
sentation de mon travail.
Enfin, j’aimerais remercier mes parents, amis et collègues pour avoir été patients et com-
préhensifs envers moi pendant la durée de ce travail.
6 Remerciements
Acknowledgments
There is a number of people that played an important role in the accomplishment of this work to
whom I would like to express my gratitude.
I would like to thank Professor Tsichritzis, who followed my work from the very start, for
trusting me and providing me with the necessary support for this thesis. He allowed me not only
to accomplish this work but also gave me the opportunity to learn a lot.
I would like to thank Professor C. Pellegrini who by accepting the direction of this thesis
made it possible for me to carry out this work.
I would like to thank Professor A. Yonezawa for doing me the honor of accepting to be my
external reader and for his encouragement for this and future work.
There are several reasons for thanking Doctor O.M. Nierstrasz. To make a long story short,
I would like to thank him, among others, for getting me interested, a long time ago, in process
calculus, for reading and commenting on several earlier versions of this thesis and for being al-
ways ready to engage in stimulating discussions.
I would also like to thank L. Dami and J. Vitek for their encouragement, which has been
invaluable, and their acute comments and suggestions that allowed me to dramatically improve
the presentation of this work.
Finally, there is a large number of people, my parents and colleagues among others, that
had to endure the peculiar moods into which I was often driven during this period and whom I
would like to thank for their understanding.
Contents
Résumé 1
1 Introduction ..................................................................................................................1
1.1 La Conception des Langages à Objets Concurrents ...........................................1 1.2 La Spécification de la Sémantique des Objets Actifs .........................................2 1.3 Contributions ......................................................................................................3
2 Choix de Conception pour des Langages à Objets Concurrents .................................3
2.1 Le Modèle d’Objets ............................................................................................4 2.2 Les Fils de Contrôle............................................................................................4 2.3 L’Interaction des Objets......................................................................................5 2.3.1 Emission des Requêtes...............................................................................5 2.3.2 Acceptation des Requêtes ..........................................................................5
3 Comparaison des Choix de Conception .......................................................................6
3.1 Critères de Conception........................................................................................6 3.2 Evaluation des Choix de Conception..................................................................7 Modèles d’Objets............................................................................................7 Mécanismes d’Interaction et Fils de Contrôle ................................................7
4 Description Sémantique des Langages à Objets Concurrents ......................................8
5 Conclusion ...................................................................................................................9
CHAPTER 1
Introduction 11
1.1 Object-Oriented Programming ...............................................................................12
Objects and Messages...................................................................................12 Classes and Class Inheritance .......................................................................13 Substitutability, Types, Subtypes and Polymorphism ..................................13
1.2 Designing Concurrent Object-Oriented Languages ...............................................15
1.3 Specifying the Semantics of Active Objects ...........................................................17
1.4 Contributions ..........................................................................................................18
1.5 Thesis Overview .....................................................................................................19
2 Contents
CHAPTER 2
Issues in the Design and Implementation ofthe Concurrent Object-Oriented Language Hybrid 21
2.1 Overview of Hybrid ................................................................................................22
Object Types .................................................................................................22 Object Interaction and Concurrency .............................................................23
2.2 The Concurrency Features ......................................................................................26
2.2.1 Local Delays With Delay Queues..................................................................27 2.2.2 Remote Delays With Delegated Calls ...........................................................28 2.2.3 Using Delegated Calls and Delay Queues for Local Delays .........................29
2.3 An Implementation of The Hybrid Concurrency Model ........................................30
2.3.1 Implementing the Concurrency Model ..........................................................32 2.3.2 Efficiently Supporting the Active View of Objects.......................................32
2.4 The Integration of the Concurrency and Object-Oriented Features ........................33
2.4.1 Encapsulation and Intra-Object Concurrency................................................34 2.4.2 Combining Synchronization and Inheritance ...............................................35 2.4.3 Data Abstractions with Concurrent Implementations....................................36
2.5 Summary .................................................................................................................37
CHAPTER 3
A Design Space for Concurrent OOPLs 39
3.1 A Design Space for Concurrent OOPLs .................................................................40
3.2 Concurrent Object Models ......................................................................................40
3.3 Internal Concurrency ..............................................................................................41
3.4 Constructs for Object Interaction ............................................................................43
3.4.1 The Client’s View - Issuing Requests............................................................43 One-way Message Passing............................................................................44 Remote Procedure Call .................................................................................44 Proxies ..........................................................................................................45 3.4.2 The Server’s View - Constructs for Accepting Requests ..............................45 Unconditional acceptance .............................................................................45 Explicit acceptance .......................................................................................46 Activation conditions...................................................................................46 Reflective computation .................................................................................47
3.5 Classification of Existing Languages .....................................................................47
3.5.1 The Orthogonal Approach .............................................................................47 Smalltalk-80 .................................................................................................47 Emerald ........................................................................................................48 Trellis/Owl ...................................................................................................49 ConcurrentSmalltalk ....................................................................................51 SR .................................................................................................................53 3.5.2 The Heterogenous Approach .........................................................................55 PAL ..............................................................................................................55
Contents 3
Eiffel // .........................................................................................................55 ACT++ .........................................................................................................56 3.5.3 The Homogeneous Approach ........................................................................58 ABCL/1 ........................................................................................................58 ABCL/R .......................................................................................................61 POOL-T and POOL2 ...................................................................................61 Hybrid ..........................................................................................................62 SINA ............................................................................................................633.6 Summary .................................................................................................................65
CHAPTER 4
Comparing the Design Alternatives with Respect to Software Reuse 69
4.1 Language Design Requirements for Reusability ....................................................70
4.2 Comparing the Language Design Choices ..............................................................71
4.2.1 An Example Application ...............................................................................71 4.2.2 Exploring the Language Design Space..........................................................73
4.3 Concurrent Object Models ......................................................................................73
4.4 Thread Structure and Object Interaction Mechanisms ............................................73
4.4.1 Sequential Objects .........................................................................................74 RPC...............................................................................................................74 One-Way Message Passing...........................................................................75 Build-in Support for Courier Proxies............................................................76 More Flexible Request/Reply Mechanisms..................................................77 4.4.2 Multi-threaded Objects ..................................................................................78 Quasi-Concurrent Approaches......................................................................78 Concurrent Approaches ................................................................................79
4.5 Compositionality and Finer Grain Reuse ................................................................80
4.6 Conclusions and Summary ....................................................................................82
CHAPTER 5
A Unifying Framework for Process Calculus Semantics ofConcurrent Object-Based Languages and Features 85
5.1 Basic Framework: objects, classes and messages ...................................................87
5.1.1 The Structure of Class Agents .......................................................................88 5.1.1.1 Program-Defined Classes .....................................................................88 5.1.1.2 Predefined Classes ................................................................................89 5.1.2 Remarks .........................................................................................................89 5.1.3 The Structure of Program Defined Objects ...................................................89 The Request Handler ....................................................................................90 Instance Variables.........................................................................................90 Method Agents..............................................................................................91 The Method Scheduler..................................................................................91 Self ................................................................................................................92 Objects ..........................................................................................................92
4 Contents
5.2 Defining SCOOL, a Simple Concurrent Object-Oriented Language .....................92
5.2.1 Syntax and Informal Description of SCOOL ................................................92 Expressions ...................................................................................................93 Statements.....................................................................................................94 Declarations ..................................................................................................94 5.2.2 Semantics .......................................................................................................94 Class Declarations.........................................................................................94 Variable Declarations ...................................................................................95 Method Declarations.....................................................................................95 5.2.2.1 Expressions and Statements..................................................................96 Agents Representing Expressions.................................................................96 Statements and Sequential Composition.......................................................96 Semantics of Expressions .............................................................................97 Semantics of Statements ...............................................................................98 5.2.2.2 Predefined Object Classes ....................................................................99 Process Objects .............................................................................................99 Semaphores...................................................................................................99 Booleans........................................................................................................99 Integers........................................................................................................100
5.3 Accommodating Other Object Models .................................................................101
5.3.1 Modifying the Syntax ..................................................................................101 Declarations ................................................................................................101 Statements...................................................................................................102 Expressions .................................................................................................102 5.3.2 Semantics .....................................................................................................102 Class Declaration ........................................................................................102 Method Scheduling .....................................................................................102 Semantics of Statements .............................................................................102
5.4 Class Inheritance ...................................................................................................102
5.4.1 Extending SCOOL to Support Inheritance ..................................................104 5.4.2 Agent Definitions for Modelling Class Inheritance.....................................104 Semantics of Class Declarations.................................................................106 5.4.3 Overriding Superclass Methods, Self and Super .........................................106
5.5 Considering Other Process Calculi ......................................................................107
5.5.1 Modelling COOPL Features in theπ-Calculus............................................108 5.5.2 Usingπ-Calculus Ports to Represent Object Identifiers..............................109 5.5.3 Comparing Object Identifiers ......................................................................110 5.5.4 Primitive Objects and the Semantics of Expressions...................................110
5.6 Concluding Remarks .............................................................................................112
CHAPTER 6
Conclusion 115
6.1 Summary ...............................................................................................................116
6.1.1 Language Design Framework......................................................................116 6.1.1.1 Understanding the Language Choices ................................................116
Contents 5
Object Models.............................................................................................116 Object Threads............................................................................................116 Object Interaction .......................................................................................117 6.1.1.2 Language Design Criteria ...................................................................117 6.1.2 Evaluating Design Choices and their Combinations ..................................118 Request and Reply Scheduling ...................................................................118 Internal Concurrency ..................................................................................119 6.1.3 Formally Specifying the Semantics of COOPLs and of Active Objects .....119
6.2 Open Problems and Future Research Directions ..................................................120
6.2.1 Taking Advantage of Class Inheritance in COOPLs...................................120 6.2.2 Object Behavior, Behavioral Equivalence and Substitutability...................121 6.2.3 Types as Behavioral Constraints for Active Objects ...................................122
References 125
Résumé
1 Introduction
La programmation par objets est une méthode de programmation qui consiste à construire des
logiciels structurés à l’aide d’un ensemble d’objets coopérants qui inter-agissent pour réaliser
les fonctions du logiciel. Cette approche de programmation suscite un intérêt croissant dans plu-
sieurs domaines de l’informatique car, d’une part, elle fournit un ensemble de concepts unifica-
teurs permettant d’intégrer plusieurs techniques de programmation dont les bénéfices sont déjà
largement reconnus, d’autre part, elle offre la possibilité de pouvoir réutiliser les objets, qui sont
des entités relativement autonomes, dans diverses applications.
Les bénéfices de cette méthode de programmation pour la construction du logiciel sont ex-
ploités par l’utilisation des langages de programmation à objets, qui rendent aisée la program-
mation selon cette méthode, ainsi que par des méthodes de conception, outils et environnements
de programmation qui ont comme but d’ appliquer, à grande échelle, cette approche pour la réu-
tilisation du logiciel.
La motivation de ce travail est d’élargir le domaine d’application de cette méthode de pro-
grammation et permettre de tirer parti de ses bénéfices dans la construction des systèmes con-
currents. Ceci nécessite la conception de langages de programmation à objets concurrents qui
intègrent les concepts de la programmation par objets à ceux de la programmation concurrente,
ainsi que le développement d’outils pour la description, d’une manière rigoureuse, de la séman-
tique de ces langages et du comportement des objets concurrents afin de permettre leur réutili-
sation effective.
1.1 La Conception des Langages à Objets Concurrents
Un grand nombre de notations a été utilisé pour la programmation concurrente. De plus, il y plu-
sieurs façons de combiner les concepts et les notations de la programmation concurrente à ceux
de la programmation par objets. Le problème qui se pose pour la conception des langages à ob-
jets concurrents est que une combinaison arbitraire des notations pour la programmation par ob-
2 Résumé
jets et la programmation concurrente, ne posant pas de difficultés au niveau syntaxique, ne per-
met pas l’intégration au niveau des concepts ce qui est necessaire pour tirer les bénéfices de la
programmation par objets pour la construction du logiciel concurrent. Ce problème provient de
la non-orthogonalité des concepts sous-jacents à ceux deux types de programmation.
Afin, de concevoir des langages de programmation qui permettent d’intégrer la program-
mation par objets et la programmation concurrente il est nécessaire d’étudier l’ inter-action des
concepts sous-jacents à ces deux types de programmation et de développer des critères permet-
tant d’évaluer les diverses possibilités concernant le choix des notations.
1.2 La Spécification de la Sémantique des Objets Actifs
Le développement de modèles pour la description de la sémantique des langages à objets con-
currents, à part d’être un but en soi, présente un intérêt tout particulier dans le cadre de la pro-
grammation concurrente par objets en ce qui concerne, en vue de leur réutilisation, la description
rigoureuse du comportement des objets développés à l’aide des langages à objets concurrents,
que l’on appellera par la suite objets actifs.
La description de la sémantique des langages à objets concurrents et du comportement des
objets actifs n’a fait l’objet que d’un nombre restreint de travaux de recherche. De plus, dans ces
travaux les points suivants n’ont été traités que d’une façon limitée:
• La description dans un seul modèle de l’ensemble des concepts de la programmation
concurrente par objets permettant une étude rigoureuse de leur interaction. Les appro-
ches antérieures n’ont pas pris en compte la description de sémantique de l’héritage.
• Le développement d’un modèle permettant la description et comparaison des langa-
gesà objets concurrents adoptant des approches de conception différentes. Les descrip-
tion sémantiques se sont limitées à un seul langage. Il est difficile de généraliser ces ap-
proches pour la description de la sémantique d’autres langages, surtout dans le cas où ils
sont basés sur des approches de conception différentes.
• Spécifier la sémantique des définitions d’objets d’une façon indépendante de la séman-
tique des programmes dans lequel elles apparaissent de sorte qu’elle puisse être utilisée
comme représentation rigoureuse du comportement d’objets et permettre d’établir la
compatibilité des comportements. Ce point est essentiel afin de permettre la réutilisation
des objets est de bénéficier de l’abstraction des données.
Résumé 3
1.3 Contributions
Les principales contributions de cette thèse sont: (1) Un cadre conceptuel pour l’étude de l’inter-
action de la programmation à objets et de la programmation concurrente permettant l’évaluation
des différentes approches de conception. (2) Un cadre formel pour la description de la sémanti-
que des langages à objets concurrents permettant de spécifier et comparer la sémantique des lan-
gages basés sur des approches de conception différentes et d’établir une notion formelle de com-
portement pour les objets actifs. Les points suivants résument les contributions spécifiques:
• Une étude de cas concernant l’intégration des concepts de la programmation par objets et de
la programmation concurrente, effectuée sur le langage Hybrid, qui a permis d’examiner
d’une façon concrète l’effet des choix de conception sur l’intégration de ces concepts.
• Une description de l’espace des choix de conception pour les langages à objets concurrents
permettant de représenter les possibilités de combiner les concepts de la programmation con-
currente a ceux de la programmations à objets.
• Un ensemble des critères permettant l’évaluation des choix de conception par rapport à l’in-
tégration des concepts de la programmation par objets à ceux de la programmation concurren-
te.
• L’identification d’un ensemble de façons de combiner certains choix de conception qui satis-
font ces critères.
• Le développement d’une approche cadre pour la description formelle de la sémantique des
langages à objets concurrents permettant de:
• Représenter les concepts de programmation à objets et de la programmation concurrente.
• Obtenir une notion formelle de comportement pour les objets actifs.
• Etablir des notions formelles de compatibilité de comportement.
2 Choix de Conception pour des Langages à Objets Concurrents
Pour pouvoir comparer le grand nombre des possibilités pour la conception des langages à objets
concurrents nous avons choisit de représenter les choix de conception en considérant les trois
aspects suivants:
• Le modèle d’objets: La prise en compte de l’exécution concurrente dans le concept d’objet
• Les fils de contrôle des objets: Le nombre, la création et commutation des fils de contrôle à
l’intérieur des objets
4 Résumé
• L’interaction des objets: les mécanismes et notations permettant de spécifier l’envoi et la ré-
ception de messages par les objets.
2.1 Le Modèle d’Objets
On distingue les trois approches suivantes concernant la prise en compte de l’exécution concur-
rente dans les objets:
• Orthogonale: le concept d’objet est indépendant des concepts de la programmation concur-
rente. Les objets sont des entités passives dont les opérations sont exécutées par des fils de
contrôle concurrents.
• Homogène: Les objets sont considérés comme des entités actives qui reçoivent des requêtes
pour l’exécution de leurs opérations qu’ils exécutent en temps opportun.
• Hétérogène: Il y a des objets passifs et des objets actifs. Le langage assure la protection des
objets passifs en interdisant la construction de programmes où les opérations des objets pas-
sifs peuvent être exécutés par des fils de contrôle concurrents.
2.2 Les Fils de Contrôle
En considérant le nombre et la commutation des leurs fils de contrôle on caractérise les objets
comme:
• Séquentiels: Un seul fil de contrôle correspond à chaque objet.
• Quasi-concurrents: Un seul fil de contrôle est actif à l’intérieur d’un objet et la commutation
des fils de contrôle est spécifiée par le programmeur.
• Concurrents: Il y a plusieurs fils de contrôle s’exécutant, d’un point de vue conceptuel, en pa-
rallèle.
La création des fils de contrôle à l’intérieur des objets peut se dérouler suivant deux façons
non exclusives:
Par réception de message: la création des fils de contrôle est initiée par la réception d’un mes-
sage.On distinguera deux sous-cas exclusifs concernant la création des fils de contrôle par ré-
ception de message:
• Création contrôlée: la création de fils de contrôle peut être contrôlée par l’objet.
• Non-contrôlée:la création de fils de contrôle se passe automatiquement à l’arrivée d’un
message.
Résumé 5
• création explicite: la création des fils de contrôle a lieu par l’exécution, par un fil de contrôle
actif, d’une instruction prévue à cet effet.
2.3 L’Interaction des Objets
Pour examiner les mécanismes permettant l’interaction des objets on va considérer séparément
les cas d’émission et de réception des requêtes par les objets se trouvant, respectivement, dans
les rôles de client et serveur.
2.3.1 Emission des Requêtes
On distingue entre les mécanismes qui incorporent ou non une notion de réponse à une requête:
• One-way messages: la notion de réponse n’est pas prise en compte par ces mécanismes. L’en-
voi et obtention de réponse a lieu à travers des messages qui au niveau du langage ne se dif-
férencient pas des messages utilisés pour des requêtes.
• Request/Reply: Ces mécanismes incorporent une notion de réponse à une requête. Il y a cepen-
dant des variations considérables en ce qui concerne le contrôle qui peut être exercé par le cli-
ent pour l’obtention de la réponse. On distingue les catégories suivantes de mécanismes re-
quest/reply:
• Remote procedure call: le client doit attendre pour l’obtention de la réponse de manière
synchrone.
• Par Proxies: le client ne pas obliger d’attendre la réponse, des objets intermédiaires, plus
ou moins explicites, sont utilisées comme pour l’obtention de la réponse. Le client ob-
tient la réponse, de manière asynchrone par rapport au serveur, par ces objets intermédi-
aires.
2.3.2 Acceptation des Requêtes
On distingue entre acceptationconditionnelle et non-conditionnelle. L’ acceptation non-condi-
tionnelle se caractérise par l’absence de mécanismes pour contrôler l’acceptation des requêtes.
La réception d’un message a comme effet l’exécution de l’opération correspondante conforme-
ment aux propriétés des fils de contrôle des objets.
Les approches suivantes peuvent être utilisées dans le cas de l’acceptation conditionnelle
pour contrôler l’acceptation des requêtes:
• Acceptation explicite: l’acceptation a lieu par l’exécution d’une instruction par un fil de con-
trôle de l’objet spécifiant explicitement les requêtes à accepter.
6 Résumé
• Conditions d’activation: Les opérations sont associées à des conditions sur l’état de l’objet
qui doivent être satisfaites pour l’acceptation et exécution d’une requête. Les conditions sont
spécifiques à la représentation si elle font référence aux variables d’instance de l’objet ou
abstraites si elles utilisent une autre approche pour déterminer l’état de l’objet.
• Réflection: la réception d’un message déclenche l’exécution d’une opération dans un méta-
objet. Le méta-objet peut examiner le contenu du message et l’état de l’objet et en conséquen-
ce exécuter l’opération correspondante ou mettre le message dans une file d’attente.
3 Comparaison des Choix de Conception
Afin de comparer les différents choix de conception et leur combinaisons nous avons développé
une série de critères d’évaluation. Ces critères sont basés sur le principe que le langage devrait
rendre aisée la réalisation d’objets qui opéreront correctement en imposant un minimum de res-
trictions sur leur environnement d’utilisation et sur le comportement des objets avec lesquels ils
seront amenés à interagir.
3.1 Critères de Conception
Un langage de programmation à objets offrant une intégration adéquate des concepts de la pro-
grammation par objets et ceux de la programmation concurrente devrait remplir les conditions
suivantes:
1. Protection, exclusion mutuelle: L’intégrité de l’état des objets doit être protégée des ap-
pels concurrent
2. Transparence de l’ordonnancement d’acceptation des requêtes: Il doit être possible
d’ordonnancer l’acceptation des requêtes en utilisant les informations relatives à la re-
quête et à l’état de l’objet. L’ordonnancement des requêtes doit être, dans la mesure du
possible, invisible aux objets clients.
3. Concurrence intra-objet: Il doit être possible d’utiliser la concurrence intra-objet dans la
réalisation des objets afin de permettre l’acceptation de plusieurs requêtes concurrentes
ou de réaliser la fonctionnalité des objets par des algorithmes parallèles. De plus, la con-
currence intra-objet doit être invisible aux clients de l’objet.
4. Transparence de l’ordonnancement d’acceptation des réponses: Il doit être possible de
permettre l’ordonnancement flexible de l’obtention des réponses sans que cela implique
la coopération des objets appelés.
Résumé 7
5. Compositionalité, programmation incrémentale: Outre le fait qu’il doit être possible de
développer des objets réutilisables dans différentes applications, les notations utilisées
pour la programmation concurrente doivent pouvoir se combiner avec le mécanisme de
l’héritage et favoriser la programmation incrémentale.
3.2 Evaluation des Choix de Conception
Pour l’évaluation des choix de conception et de leurs combinaisons, effectuée dans le chapitre
4, on se sert d’un exemple d’application concurrente qui nous permet d’identifier et d’illustrer
des situations où certains choix de conception s’avèrent inadéquats par rapport à nos critères.
Procédant ainsi, “par élimination” on arrive à l’identification d’un ensemble des combinaisons
des choix de conception qui satisfont nos critères de conception que l’on présente ci dessous.
Modèles d’Objets
Concernant le modèle d’objets, c’est l’approche homogène qui est la plus satisfaisante. Elle
remplit d’une part la condition (1) en assurant automatiquement la protection de l’état interne
des objets vis à vis des appels concurrents, d’autre part la condition (5) en supportant, au con-
traire de l’approche hétérogène, une seule sorte d’objet pouvant être utilisée dans toutes les ap-
plications.
Mécanismes d’Interaction et Fils de Contrôle
Les conditions (2) et (4) concernant l’ordonnancement des requêtes et des réponses, peuvent être
satisfaites par tous les choix concernant les fils de contrôle pourvu qu’ils soient combinés avec
un choix approprié des mécanismes d’interaction d’objets.
Dans le cas des objets séquentiels, n’ayant qu’un seul fil de contrôle, il est nécessaire d’a-
voir un mécanisme qui permette de retarder l’exécution d’une requête et d’obtenir la réponse aux
requêtes sans suspendre l’exécution du fil de contrôle. La meilleure approche dans ce cas est de
combiner les messages à sens unique avec l’appel de procédure à distance (RPC). Ceci permet
á un objet de tirer avantage dans son implantation des la flexibilite des messages à sens unique
tout en présentant à ses clients une interface RPC. En ce qui concerne l’ordonancement des ré-
ponses il serait aussi envisageable d’utiliser une approche basée sur desproxies, néanmoins il
faudrait un mécanisme permettant de combiner l’ordonancement des requêtes et des réponses,
ce qui fait défaut dans les approches à base de proxies que nous avons examinées.
Dans le cas des objets concurrents et quasi-concurrents, afin de permettre de satisfaire les
conditions (3) et (4) il est nécessaire de combiner le choix de RPC, utilisé comme le mécanisme
principal pour l’inter-action des objets, soit avec la création explicite de fils de contrôle soit avec
8 Résumé
des messages à sens unique ou des proxies pour permettre à un fil de contrôle d’émettre des re-
quêtes pouvant être exécutées en parallèle.
Dans le cas d’objets quasi-concurrents, afin de permettre l’ordonnancement des réponses
(4), le blocage d’un fil de contrôle suite à un appel en RPC ou pour l’obtention d’une réponse
par l’intermédiaire d’un proxy, doit entraîner la commutation d’un autre fil de contrôle.
La concurrence intra-objet peut être supportée de manière satisfaisante soit par les objets
concurrents soit par la réalisation de la fonctionalité d’un objet par un ensemble d’objets concur-
rents, pourvu que le choix des mécanismes d’interaction d’objets soit adéquat pour l’ordonann-
cement des requêtes et des réponses et que la sémantique du langage soit telle qu’un objet im-
plantée par un ensemble d’objets concurrents soit substituable dans tout contexte avec un objet
unique offrant la même fonctionalité à ses clients.
Ces deux approches pour la concurrence intra-objet sont complémentaires et il est intéres-
sant de les avoir dans un même langage afin de pouvoir les utiliser dans les situations auxquelles
elles conviennent le mieux. L’approche des objets concurrents rend très facile la réalisation des
objets qui acceptent, en parallèle, plusieurs requêtes qui ne modifient pas l’état de l’objet. La ap-
proche multi-objet est intéressante pour réaliser la fonctionnalité d’une classe d’objets en utili-
sant des objets de classes existantes.
4 Description Sémantique des Langages à Objets Concurrents
Pour la description de la sémantique des langages à objets concurrents nous avons pris l’appro-
che, utilisée par Milner dans [58], qui consiste à spécifier la sémantique d’un langages concur-
rents par “traduction” au calcul des processus CCS. La spécification de la sémantique des lan-
gages de programmation selon cette approche, quoique opérationelle, a une forte ressemblance
aux approches dénotationelles[35][74][78]. La spécification de la sémantique d’un langage de
programmation est donnée comme une fonction faisant correspondre à chaque construction syn-
taxique du langage un terme du calcul des processus, le “sens” des constructions syntaxiques
composées étant défini en faisant appel à celui de ses composantes directes.
Afin de simplifier la description de la sémantique des langages et de permettre de repré-
senter et comparer les divers choix de conception de langages, nous avons établi un ensemble de
conventions pour la représentation des concepts de la programmation par objets concurrents en
CCS, et nous avons défini, en tant que processus parametrisées par des processus, un ensemble
d’opérateurs CCS dérivées permettant de capter directement les concepts de la programmation
concurrente par objets.
Résumé 9
Nos choix concernant la représentation des concepts de la programmation par objets en
CCS ont été faits de façon à permettre de décrire facilement et de comparer la sémantique de
langages basés sur des choix de conception différents. Ainsi, l’ensemble de règles de représen-
tation et les définitions d’opérateurs dérivés fournissent un cadre général pour la description sé-
mantique formelle des langages de programmation à objets concurrents. La définition d’un en-
semble de langages nous a permis d’illustrer l’approche pour la représentation d’un grand nom-
bre de concepts de la programmation concurrente par objets comprenant aussi l’héritage dont la
sémantique n’avait pas été spécifiée, auparavant, dans un même cadre que les notations pour la
programmation concurrente afin de permettre d’étude de leur interaction.
Cette approche pour la description sémantique a aussi le bénéfices de pouvoir tirer avantage
du formalisme du calcul de processus CCS afin d’étudier la conception des langages et le com-
portement des objets. Une conséquence importante de ceci, ainsi que du fait que la sémantique
du comportement d’une classe est spécifié par un processus CCS, est qu’on obtient une notion
formelle de comportement et d’équivalence de comportement des objets induite par l’équivalen-
ce des processus CCS correspondants.
5 Conclusion
Afin de pouvoir utiliser la programmation par objets et tirer ses bénéfices pour la construction
d’applications concurrentes, il est essentiel d’une part, d’avoir des langages de programmation
permettant une intégration adéquate des concepts de la programmation concurrente à ceux de la
programmation par objets, et d’autre part, d’avoir des outils formels qui permettent la descrip-
tion rigoureuse de la sémantique de ces langages, et qui fournissent des notions formelles du
comportement et de la compatibilité du comportement des objets.
Concernant la conception des langages de programmation à objets concurrents, nous avons
étudié l’interaction des concepts de la programmation par objets et de la programmation concur-
rente et produit un cadre conceptuel permettant d’évaluer les choix de conception des langages.
En utilisant ce cadre on a identifié un ensemble de combinaisons de choix de conception pour
les langages à objets concurrents offrant une intégration adéquate de ces concepts.
Pour la description de la sémantique des langages à objets concurrents nous avons produit
une formalisation des concepts de la programmation à objets concurrents dans le calcul de pro-
cessus CCS permettant la description formelle des divers choix de conception et qui a permis
d’ obtenir des notion formelle, essentielles en vue de leur réutilisation, du comportement et de
compatibilité de comportement des objets concurrents.
CHAPTER 1
Intr oduction
Object-Oriented (OO) programming [25][34][56][64] has become extremely popular for the de-
sign and construction of software systems. It is a programming approach that advocates the con-
struction of systems structured as a collection of interacting software objects that reflect their
application domain counterparts. It also provides a framework that encompasses a host of pro-
gramming techniques such as modularity, encapsulation, data abstraction, polymorphism and in-
heritance that are useful for the construction and maintenance of software and that promote soft-
ware reusability[12]. The full deployment of OO techniques and their potential for software re-
usability[57][82] is best achieved on one hand by the use of object-oriented programming
languages (OOPL) which directly support the object-oriented concepts and on the other by de-
sign methods [30][40][89], techniques and tools [33] that aim at larger-scale reuse and assist the
construction and dissemination of reusable software.
The motivation of this work is to take advantage of object-oriented programming tech-
niques and their potential for software reusability for the construction of concurrent software
systems. There are two important issues to consider for approaching this goal. The first is the
design of Concurrent Object-Oriented Programming Languages (COOPLs) that integrate the
object-oriented techniques with concurrent programming. The second is the development of se-
mantic models that provide a rigorous basis for the design and development of concurrent sys-
tems following an object-oriented approach.
The problem that is posed by the design of COOPLs is that issues of concurrency, contrary
to what one might naively expect, are not orthogonal to object-oriented concepts. The interfer-
ence of the concurrency and object-oriented features makes it hard to achieve their satisfactory
integration.
Object-Oriented Programming12
The development of semantic models for the description of the semantics of concurrent ob-
ject-oriented features is important both for analyzing the various language features and for the
rigorous description of the behavior of active objects. A rigorous way to describe the behavior
of active objects independently of particular implementations is crucial in order to be able to re-
use objects across applications.
In section 1.1 we review the main concepts underlying object-oriented programming and
the benefits entailed by following an OO approach for software development. The purpose of
this section is to provide some background on object-oriented programming and set up the stage
for presenting in 1.2 and 1.3 the problems addressed by this work. Namely, the designof
COOPLs and the development of models for the semantic description of OO languages and sys-
tems.
1.1 Object-Oriented Programming
Object-oriented programming is a programming approach that views software systems as col-
lections of objects interacting by exchanging messages. Central to the approach are the concepts
of object and message.
Objects and Messages
An object is an identifiable entity, usually modelling an application domain counterpart, that
supports a number of operations. The set of supported operations, also called methods, consti-
tutes the object’s interface and determines what one can do with the object, e.g. use a service
provided by it, find out about or modify the state of the application domain entity modelled by
the object. To invoke an object’s operation one sends a message requesting it to execute its op-
eration and, eventually, return a result.
The message metaphor is used to emphasize that the caller has no control over the exact
actions that are performed at the receiver object. This is realized by the means ofdelayed binding
where the code executed is determined not only by the requested operation but also by the way
that the operation is implemented by the receiver.
The state of an object persists during its entire lifetime and is maintained in the object’sin-
stance variables. The scope of instance variables is confined to the object’s operations so that
updates or inquiries concerning the object’s state may only take place indirectly by invoking an
appropriate operation. Thisencapsulation of the object’s state and operations has several bene-
fits:
Chapter 1 13
• It enhances modularity [70][71] by establishing and enforcing well defined boundaries
between objects at the operation interface. Furthermore, the modular decomposition of a
system is in terms of objects that represent entities of the application domain. This pro-
duces modular units that are more likely to be reused across application than modules
that occur from the decomposition of an application’s functionality for managerial pur-
poses.
• It provides support fordata abstraction [49] by insulating the programs that use objects
from the way that objects are implemented and protecting the integrity of the object state.
Data abstraction supports programming at a higher level of abstraction and the possibil-
ity to modify or extend the implementation of objects without affecting already devel-
oped programs that used them.
Classes and Class Inheritance
Classes specify the structure of objects and the implementation of their operations and act as
templates for the creation of instances of the class.
Class inheritance is a mechanism that may be used for the incremental definition of a class
in terms of some already defined classes that are called itssuperclasses or parent classes. The
newly defined class is called a subclass of its superclasses. If no more than one parent class may
be used in defining the class then the inheritance mechanism is called single inheritance and
multiple inheritance otherwise.
Class inheritance allows class definitions to be reused in the definition of new classes and
has been considered as a criterion to characterize a language as object-oriented [87]. However,
it has been a source of problems because of the way that it has been included in some program-
ming languages. As discussed by Snyder in [75] the encapsulation of objects, which is an essen-
tial feature of object-oriented programming, is violated by the inheritance mechanism of some
languages. Other problems are, as will see in the next section, caused by using the class inherit-
ance hierarchy for defining the type systems of some object-oriented languages and, as we dis-
cuss in section 1.2, its interference with the concurrency mechanisms in the case of COOPLs.
Substitutability, Types, Subtypes and Polymorphism
Late binding makes it possible to write programs that operate on objects of any class provided
that the operations required by the programs are supported by the class and that the behaviors
provided by the classes are compatible in some sense. This idea is known as the principle ofsub-
Object-Oriented Programming14
stitutability. Any object may be used in a program context for which it supports the required op-
erations and behavior independently of the way it is implemented.
With untyped object-oriented languages any object may be used in any program context
and it is the responsibility of the programmer to prevent run-time errors by ensuring that objects
satisfy the requirements of substitutability. Typed object-oriented languages assist the program-
mer through compile time type-checking to ensure, to some extent, that objects satisfy the sub-
stitutability requirements.
Unlike classes which provide the information necessary for the creation of their instances,
types are motivated by compile time type-checking and express constraints on the objects usable
in some program context. Depending on the notion of types supported, object-oriented languag-
es express different notions of object compatibility that vary in their ability and flexibility to cap-
ture substitutability. Several such notions of compatibility are discussed by Wegner and Zdonik
in [88] for examining various forms of incremental modification supported in object-oriented
languages. Two of these aresignature compatibility andbehavior compatibility.
Signature compatibility is based on the signature of operations applicable to the objects of
the type and is behind most notions of object-oriented types. Type-checking based on signature
compatibility will ensure that objects support all the operations, with the appropriate number of
arguments and compatible argument types, that are required in some program context.
Behavior compatibility is a semantic notion and it can be expressed by associating an alge-
bra with the signature of the type [88] or axiomatically[6][37] by associating operations with
preconditions and postconditions on some abstract representation of the states of the objects of
the type.
A type system ispolymorphic[26] if objects may satisfy the constraints required by more
than one type specification. In such a type system a type S is called asubtype of a type T if every
object that qualifies as an object of type S also qualifies as an object of type T. Polymorphic type
systems are very important for object-oriented programming. They can be used for making sure
at compile time that the requested operations are effectively supported by the invoked object
without imposing any further constraint on the object’s class.
In practice the approaches that have been followed by strongly typed object-oriented lan-
guages are the following:
• Collapse the notion of type with that of a class and use the class-subclass relationship as
a subtype relationship.
Chapter 1 15
• Specify types in terms of the signatures of the supported operations and use some notion
of signature compatibility motivated by substitutability to specify type compatibility and
subtypes.
• Use some form of signature compatibility augmented by some means to specify more
about the semantics of the type. This is done to allow the programmer to associate more
semantic information with signatures to prevent cases where the signatures of different
object classes are accidentally compatible. This approach is illustrated by POOL-I[7].
The approach that identifies types with classes and subtyping with inheritance makes type-
checking easy but has drawbacks. It unduly restricts substitutability and constrains the use of
class inheritance. There may be classes that are not in a class-subclass relationship that are sig-
nature and behaviorally compatible, however, instances of such classes are not interchangeable.
With respect to the use of class inheritance for code reuse, the substitutability principle requires
subclasses to inherit and provide to their clients all the superclass’s methods although just some
may be useful for defining the subclass.
Type systems incorporating the notions of types discussed, their use in object-oriented lan-
guages and their underlying theory are presented in [20]and [26]. Wegner and Zdonik in [88]
discuss the relation between types, classes, inheritance and subtyping. Some of the drawbacks
of identifying subtyping and inheritance in a language are discussed in [41].
1.2 Designing Concurrent Object-Oriented Languages
To make use of object-oriented techniques for constructing concurrent applications it is neces-
sary to provide a way to express concurrent execution and synchronization in a object-oriented
language. This may be accomplished by using a variety of concurrent programming nota-
tions[9]. Furthermore, there are various ways in which these notations have been, or may be,
combined with OO constructs in COOPLs[69].
However, arbitrary combinations of concurrency and object-oriented features may not pro-
duce the desired effect. Issues of concurrency are not orthogonal to object-oriented ones and, as
has been noticed recently by a number of researchers [17][41][68][80], the interference of con-
currency and object-oriented features defeats the purpose of object-oriented techniques for the
development of concurrent software.
A first approach that may come to one’s mind for the design of a COOPL is to introduce in
a object-oriented language the notion of concurrent process and some mechanism for process in-
teraction independently of objects. With this approach there are two independent concepts: con-
Designing Concurrent Object-Oriented Languages16
current processes and objects, in terms of which applications may be structured. The disadvan-
tage of such an approach is that it weakens modularity. The boundaries of the system compo-
nents produced from applying each concept independently may intersect so that neither of the
two structuring concepts may produce self-contained modular units. As the process communi-
cation-synchronization boundary may be different from the object interface, objects cannot be
implemented independently from the process structure of an application. For instance, objects
should be implemented differently according to whether they are used in a program where they
will be shared by concurrent processes. Shared objects should be implemented in such a way that
their internal state is protected from the concurrent invocation of their methods.
A second approach is to integrate the concepts of object and process into the concept of ac-
tive object having its own single thread of control. This has the benefit that there is a single con-
cept for structuring applications and shows better modularity. However, it restricts the number
of threads that can be used to implement objects and it may thus weaken the power of data ab-
straction when multiple threads are needed for the object’s implementation. In principle it would
be possible to use objects to represent internal control threads, however as we will see depending
on the features supported by a language this approach for the implementation of objects may not
always be hidden behind an object’s interface and weakens thus the support for data abstraction.
Another aspect to consider in the design of the concurrency constructs and their integration
with object-oriented features is the use of class inheritance. Depending on the design of the con-
currency constructs of the language class inheritance may be useless because all inherited meth-
ods may have to be rewritten. In other cases, in order to properly synchronize the execution of
methods defined in a subclass with inherited methods, subclasses have to access the instance
variables of their superclass, thus violating encapsulation. In some approaches it is attempted to
separate the concurrency constructs from the code of the methods so that inheritance may still
be used for the “sequential” part of the object. Yet, in other approaches it is attempted to specify
independently, reuse and specialize the specification of synchronization policies for the execu-
tion of methods.
In order to develop languages that achieve a graceful integration of concurrency with ob-
ject-oriented features it is essential to have a deeper understanding of the interaction of the issues
of concurrency with the object-oriented concepts and to develop criteria for establishing their
integration. The various language design approaches may then be compared by their impact on
the integration of concurrent programming with object-oriented techniques in several aspects of
language design.
Chapter 1 17
An approach that may be followed for evaluating whether the different design choices pro-
vide satisfactory support for object-oriented programming is to construct examples that show
that the features under examination fail to support object-oriented techniques. With this ap-
proach we are able to identify constructs and combinations of constructs that are inadequate for
concurrent object-oriented programming. However, this approach for evaluating languages re-
quires to construct appropriate examples and uses of the language that reveal the interference of
features or their inadequate support for object-oriented techniques in various aspects of the lan-
guage design. This in some cases may only be possible after a language has been designed and
implemented. The development of a semantic framework for COOPL, discussed in the next sec-
tion, will be useful for providing a more rigorous approach for examining the interaction of fea-
tures and representing and comparing the various design alternatives.
1.3 Specifying the Semantics of Active Objects
Apart from the fact that the semantic description of COOPLs, and object-oriented features more
generally, is an interesting problem in its own right, several practical benefits, discussed below,
are to be drawn from a semantic model for describing the behavior of active objects.
Semantic descriptions of COOPLs have been scarce. Furthermore, the following important
issues underlying the semantics of concurrent object-oriented programming have been ad-
dressed, if at all, to a limited extent:
• The description of the semantics of the full range of object-oriented features so that it is
possible to examine their interaction in a formal setting. For instance inheritance has not
been taken into account in previous semantic descriptions of COOPLs.
• A framework in which the different design approaches taken by COOPLs may be cap-
tured and compared. Most semantic descriptions have concentrated on a particular lan-
guage and it is not clear whether and how languages based on different design approach-
es may be accommodated within the same semantic framework.
• The semantics should assign meanings to individual objects rather than complete pro-
grams. Moreover, the meaning assigned to objects should be useful as a notion of behav-
ior that abstracts from their implementation and should allow various notions of behav-
ioral compatibility among objects to be developed.
The last point is extremely important for taking advantage of object-oriented techniques for
developing concurrent systems. In order to reuse objects, take advantage of principle of substi-
Contributions18
tutability and describe behavioral dependencies among components of application frameworks
a clear notion of object behavior is needed.
The approach that we have taken for the semantic description of COOPLs which fully ad-
dresses the first two points assigns as the meanings of individual objects terms of the Calculus
of Communicating Systems (CCS)[58]. This allows us to use all the underlying formal frame-
work for discussing the issues of behavior compatibility, substitutability and expressing and ver-
ifying behavioral constraints for objects.
1.4 Contributions
The main contributions of this thesis are: (1) A conceptual framework for understanding the in-
teractions of concurrency and object-oriented features and for comparing language design choic-
es with respect to the integration of concurrency and object-oriented programming; (2) A formal
framework for describing the semantics of a wide range of COOPLs and for providing a rigorous
notion of behavior for active objects. The points below summarize the specific elements of these
contributions.
• A case study of the integration of concurrency and object-oriented features in the language
Hybrid that concretely shows the effect of language design choices in integrating concurrent
and object-oriented programming. It identifies both choices that are problematic because of
the interference between features as well as choices that achieve a successful integration of
concurrency and object-oriented concepts.
• A design space for COOPLs that captures the different approaches for the combination of con-
currency and object-oriented features.
• A set of requirements for evaluating the support provided by COOPLs for object-oriented pro-
gramming and for comparing the different design approaches.
• A set of guidelines for the combination of design choices that successfully address the above
requirements.
• The development of a formal framework for describing the semantics of COOPLs that:
• Captures the standard OO features and concurrency and the different language design ap-
proaches.
• Models the semantics of individual object classes by CCS agents providing thus a rigor-
ous notion of object behavior and behavior equivalence induced from agent equivalence.
Chapter 1 19
• Makes possible to use the underlying CCS theoretical framework to reason about the be-
havior of objects.
1.5 Thesis Overview
Chapter 2 discusses in more detail the difficulties of integrating concurrency and object-oriented
programming. The discussion is carried out with respect to a particular language, Hybrid[62],
and is based on our own experience gained through our participation in the design and imple-
mentation of a prototype for this language[42][68].
In chapter 3 , in order to understand what are the different ways for combining concurrency
and OO features, we develop a design space capturing the essentially different approaches for
the design of COOPLs with respect to three separate aspects of language design. We then survey
a number of existing languages and state where they are situated in this design space.
Chapter 4 presents a list of requirements for the design of COOPLs to achieve a successful
integration of concurrency and object-oriented programming. Then, we explore the design space
presented in chapter 3 and examine how these requirements are addressed by the various design
choices. A number of examples and re-use scenarios are used for identifying the inadequacy of
certain design choices from an OO programming point of view.
Chapter 5 addresses the problem of the formal description of the semantics of object behav-
iors and the semantics of COOPLs. We take the approach of giving the semantics of objects by
translation to terms of a process calculus. We propose a framework, based on CCS[58], for such
a semantics and show how the different design choices discussed in chapter 3 can be accommo-
dated.
In chapter 6 we discuss a number of promising directions for future research. These include
the development of behaviorally motivated conformance relations for objects, further use of the
framework discussed in chapter 6 to more rigorously compare language and application designs
with respect to their re-use potential.
CHAPTER 2
Issues in the Design andImplementation of the ConcurrentObject-Oriented Language Hybrid
Hybrid is a concurrent object-oriented language and runtime system that was developed at the
University of Geneva. The aim of the project was to integrate the basic object-oriented concepts
of encapsulation, data abstraction and inheritance with strong typing, concurrency, persistence
and distributed execution. The integration of all these features in a single system was innovative
as, to our knowledge, there was no other language/system which had achieved a similar goal,
and still the clean integration of some of these features remains an open problem. The original
language design was presented in [62] and the design and implementation of a prototype, includ-
ing a substantial subset of the projected features, is described in [42].
The implementation of the prototype uncovered difficulties in the integration of several
features as well as semantic flaws in the original language design[62][63]. Thus, the language
has undergone some changes in order to patch these flaws, and some features, whose integration
deserved more examination, were left out to make the implementation easier. The examples and
further discussion on Hybrid, unless explicitly stated, are about the implemented language pro-
totype [42].
The experience that was gained through the development of the prototype and the further
study of the design of Hybrid by us [68] as well as by other researchers [41][80] brought out
several issues concerning the integration of object-oriented concepts with other features and
concurrency in particular.
Overview of Hybrid22
In this chapter, using Hybrid as a concrete example, we discuss several issues concerning
the design and implementation of concurrent object-oriented languages. We start with a short
overview of the Hybrid language that provides the necessary background for understanding the
issues discussed in later sections. Then we present the concurrency features and their implemen-
tation and discuss their integration with object-oriented features. We conclude by summarizing
the general issues in the design of COOPLs, revealed through our experience with Hybrid, con-
cerning the successful application of object-oriented techniques for the construction of concur-
rent software.
2.1 Overview of Hybrid
Hybrid is a strongly typed language which, by abstract typing, subtyping and dynamic binding,
combines most of the advantages of static (compile time) type checking with the flexibility of
non statically typed languages as Smalltalk[34].
Object Types
The language constructs for type definition include a number of predefined object types such as
integers and booleans, more conventional type constructors such as structures and enumerated
types, and anabstract construct that supports the definition of abstract data types. The use of the
abstract type constructor is shown below in the definition of a stack of integers.
type integerStack:
abstract{
push: integer ->;
pop: -> integer;
empty: -> Boolean;
full: -> Boolean;
}
private{
instance variables
var buffer: array[1..100] of integer;
var top:= 0: integer;
implementation of the operations
empty(): -> Boolean;
{ return( top =? 0); }
full(): -> Boolean;
{ return( top =? 100); }
...more operation implementations ...}
Chapter 2 23
All objects are typed. We distinguish between theeffective andactual type of objects. The
effective type determines the operations that are supported and that determine the object’s inter-
face. The actual type of an object determines the representation of its internal state and the im-
plementation of its operations.
Type equivalence is defined as structural equivalence[2] on the effective object types. Two
types are equivalent if their instances support the same number of operations which have the
same names and number of arguments, and the types of arguments and return types are equiva-
lent. Predefined types such as integer and character, provide the base case in this recursive def-
inition. A conformance relation on types is defined as follows: A typeS conforms to a typeT if
for every operation supported byT, S supports an operation with the same name and the types
of arguments and return values are of equivalent types.
Type checking is based on the conformance relation over the effective types of objects and
determines, at compile time, whether the types of expressions conform to the type required by
the context where they appear. This ensures that the invoked operations are effectively defined
at the interface of invoked objects.
This approach to typing and conformance accounts for polymorphism [20] in the Hybrid
type system and supports the construction of programs which operate on refined versions of con-
forming types yet to be defined. It is important to note that unlike other typed object-oriented
languages, such as C++ [76] and Eiffel [54] where conformance requires that an inheritance link
exists between conforming types, the typing issues are kept separate from inheritance as in
POOL-I[7].
Hybrid also supports the definition of parametrized types and provides the possibility to
constrain the type parameters to be equivalent or conform to some existing type.
Object Interaction and Concurrency
Objects in Hybrid are active entities that interact by invoking one another’s operations in a re-
mote procedure call fashion. An object sends acall message to another, requesting it to execute
one of its methods, and then waits until the results are returned by areturn message. Arguments
to operation invocations are passed by value. This decision was made in order to support distrib-
uted execution and to provide more control on the use of an object’s subobjects (objects stored
in its instance variables) by not allowing them to be referenced by other objects. Object sharing
and a form of argument passing by “reference” is supported by explicit use ofoidswhich are
objects holding references to other objects.
Overview of Hybrid24
The thread of nested remote procedure calls amongst a set of objects is called anactivity.
An activity is created by invoking an operation defined as areflex.The invocation of a reflex
takes place by sending astart message after which the sender proceeds in parallel with the re-
ceiver.
A collection of objects consisting of a “top-level” object and its subobjects is called ado-
main. When an object is created it is possible to specify whether the new object is in the domain
of its creator or if it is created as an independent top-level object. A domain is the unit of paral-
lelism and it may be in one of the three states:active, blocked or idle. It is active when an object
is executing an operation in response to a call or start message. It is blocked when it has invoked
the operation of another object and waits for the reply. It is idle if it is neither active nor blocked.
An object in a idle domain may accept any kind of message1 from any activity. Objects in
a blocked domain may accept return as well as call messages associated with the corresponding
activity. The possibility of accepting further call messages associated with the activity on which
the domain is blocked supports a form of “recursive” call allowing an object to call itself or its
caller without causing a deadlock.
Apart from the above rules, acceptance of call messages may be controlled in a program-
mer-defined way by thedelay queue mechanism. Delay queues are defined as instance variables
of typedelay. They may beopen orclosed and may be associated with the operations of the ob-
ject. The acceptance of call messages for an operation associated with a closed delay queue is
delayed until the delay queue is open.
Thedelegated call mechanism, explained shortly, allows an object to call an other object
without becoming blocked. A delegated call causes the domain of the calling object to become
idle. Thus, the caller or other objects in the domain may switch their attention to other activities.
This feature is made possible by supporting multiple threads within objects which execute in a
quasi-concurrent fashion.
The synchronization provided by domains and activities is very useful for computations in-
volving the coordinated execution of a collection of objects. The correctness of such a compu-
tation is based on implicit assertions on the states of participating objects. The concurrent exe-
cution of objects may cause state changes that invalidate such assertions. Domains and activities
provide the possibility to coordinate the execution of objects so that no interference may occur
by their concurrent execution.
1. it is possible for an idle object to receive a return message because of the delegated call mechanism ex-
plained next.
Chapter 2 25
For example, a bank account class,Account, supports, among others, operations for reading
its balance, and withdrawing and depositing an amount. ATeller class is used to provide restrict-
ed access to bank account operations. This class supports operations for reading an account’s
balance and withdrawing an amount under a certain limit. When a withdrawal is requested to an
instance of this class it checks that the requested amount does not exceed this fixed limit and that
sufficient funds are available in the associated bank account. It then carries out the withdrawal
by invoking the bank account’s withdraw operation.
If Teller instances and their associated accounts are independent objects the concurrent ex-
ecution of teller objects sharing an account may interfere causing the account to be overdrawn.
This situation is illustrated in figure 2.1-1 where twoTeller instances and a shared account are
shown as independent objects. The concurrent execution of requests by teller objects may take
place as follows: Both tellerobjects accept withdrawal requests at (1), (2) for amounts not ex-
ceeding the fixed limit. Then both check at (1.1) and (2.1) whether the requested amount does
not exceed the account’s balance and then proceed with the withdrawal at (1.2) and (2.2). How-
ever, if the sum of the requested amounts exceeded the account’s balance the account would be
overdrawn.
This problem, as other such problems, may be solved by having theTeller instances and the
associated account be in the same domain. As illustrated in figure 2.1-2, once a withdrawal re-
quest is accepted by one object, say Teller1, requests from other activities are delayed at the do-
(1.1)
(2.1)
(1.2)
AccountTeller1
Teller2
1
call message
completed rpc
object boundary
domain boundary
Withdraw1
Withdraw2
(2.2)
(1.1)(1.2)
Teller1
2
Withdraw1
Withdraw2
Account
Teller2(1)
(2)
Figure 2.1
The Concurrency Features26
main boundary. This is an elegant solution to this problem which allows the different access
views to accounts to be represented as separate objects classes. Moreover, no extra programming
effort is required in the implementation of theTeller andAccount classes for synchronizing the
execution of their instances.
2.2 The Concurrency Features
Hybrid includes high level constructs that directly support object interactions according to the
message passing model that was presented in the previous section. As remote procedure calls are
the primary means for expressing object interaction, the language classifies as anoperation ori-
ented language in the concurrent programming language classification of Andrews and Schnei-
der [9].
In order to motivate the presentation of the concurrency constructs of Hybrid we are going
to use the concurrency requirements of Liskov et al.[49] for the construction of distributed pro-
grams. These programs are considered to be structured as a collection of active modules acting
as servers and clients, a structure that closely matches object-oriented programs.
The main requirement formulated in [49] is that when an activity becomes blocked within
a module (object in the case of Hybrid) other activities should be able to proceed. They identify
two common situations where an activity may get blocked:local delayandremote delay.
Local delay is the situation where an object is unable to service a request because of the
temporary unavailability of a local resource. In such a case, the object should be able to set aside
this request and turn its attention to others. Moreover, not being able to set aside a request that
cannot be processed immediately may also cause unnecessary deadlocks; while being blocked
because of the unavailability of a local resource, the object would be unable to accept requests
that would made the resource available. For instance, a full bounded buffer object should be able
to accept requests for removing items in order to get to a state where further requests to insert
items can be processed.
Remote delay is the situation in which an activity is delayed within an object because of a
call to another object acting as a “lower level” server. The delay may be due to the communica-
tion delay, the time needed by the lower level server for handling the request or a local delay in
the lower level server. During this time further requests could be accepted and processed by the
object.
Chapter 2 27
2.2.1 Local Delays With Delay Queues
In Hybrid, simple forms of local delay are handled easily with delay queues. The use of delay
queues allows objects to avoid accepting a request that would lead to a local delay. An illustra-
tion of the use of delay queues for simple cases of local delays is given below by the code outline
of a bounded buffer.
type boundedBuffer : abstract {init : ->;put : string ->; uses delay;get : -> string; uses delay;
};private {
var putDelay, getDelay: delay;var buffer: strarray;...init: ->;{
...putDelay.open();getDelay.close();
}
get: -> string; uses getDelay;{
...get an item.if the buffer is now empty
getDelay.close();putDelay.open();...
}
put: string ->; uses putDelay;{
...insert an itemif the buffer is now full
putDelay.close();getDelay.open();
}}
The delay queuesgetDelay andputDelay are used for avoiding the acceptance ofget andput
requests when the buffer is empty and full respectively. Initially the delay queuegetDelay is
closed so that noget requests are accepted and the delayputDelay is open so thatput requests are
accepted and items may be inserted in the buffer. When the methodput is executed it opens the
delay queuegetDelay so thatget requests may be accepted. The method get determines whether
the buffer is empty and then closes thegetDelay delay queue. The methodput closes theputDelay
delay queue when the buffer is full.
The Concurrency Features28
In the above example, whether a request will lead to a local delay is determined by the re-
quested method and the local state of the object. However, there are cases where this information
is not sufficient and it is also necessary to know the values of the method’s arguments[15]. Such
cases are dealt with in Hybrid by combining delay queues with the delegated call mechanism. In
section 2.2.3, after we have introduced the delegated call mechanism, we will show how to han-
dle more complex cases by a combination of delay queues and delegated calls.
2.2.2 Remote Delays With Delegated Calls
The delegated call mechanism is well suited for remote delays. When an object issues a delegat-
ed call the executing thread is suspended. Another request may then be processed by another
thread. A thread that was suspended because of a delegated call is resumed after the delegated
call returns and there are no other active threads within the object.
As an example illustrating the use of the delegated call mechanism, consider an object that
operates as an administrator for a collection of worker objects. This object is acquainted with a
collection of worker objects that it uses for servicing the requests made by clients. Remote de-
lays occur when the administrator invokes a particular worker for doing the job. It would not
make sense for the administrator to wait until the worker finishes the requested work. Instead, it
should accept other requests and pass them on to other workers that would process them in par-
allel. The use of the delegated call mechanism allows the administrator to switch its attention to
another request while a call is passed on to a worker. The outline of the administrator is given
below.
type administrator: abstract {doWork(work: WorkType)-> resultType;
} ;private{
var workers: array[1..MAX] of oid of workerType;doWork(work: WorkType) -> resultType{
var workerIndex: integer;var result : resultType;
select the worker appropriate for this work,assign its index to workerIndex.Pass on the request to the worker by issuing a delegated call
result <- delegate(@workers[workerIndex].doIt(work));
gather some statistics about workers based on resultreturn the result to the caller.
Chapter 2 29
return(result);
}
}
Thedelegate(...) expression causes the executing thread to be suspended and the call mes-
sage to be passed on to the selected worker. While the worker handles the call, another call may
be accepted by the administrator. This call is handled by the implicit creation of a new thread.
However, there may not be more than one active thread at a time within an object. Suspended
threads are resumed after the delegated call has returned and there are no other active threads
within the object.
2.2.3 Using Delegated Calls and Delay Queues for Local Delays
In section 2.2.1 we mentioned that some local delays that cannot be handled by delay queues
alone can be handled by combining delay queues and delegated calls.
In order to suspend the execution of one of its methods, an object may issue a delegated call
to another object. The delegated call causes the invoking thread to be suspended and the object
is free to accept further requests. If the method invoked by the delegated call is associated with
a closed delay queue, the suspended thread in the calling object is delayed until the execution of
another method opens the delay queue. This causes the call to be accepted so that the delegated
call may return.
A typical object, used for suspending the execution of another object’s methods, would pro-
vide two methods:suspend andresume implemented as follows:
private{
var suspendDelay: Delay;
This delay is initially closed so that callers are delayed
suspend():->; uses suspendDelay;
{
Close the delay so that the next caller will be suspendedsuspendDelay.close();
}
resume(): ->;
{
suspendDelay.open();
}
}
The delay queuesuspendDelay is initially closed. An object willing to suspend the execu-
tion of one of its methods issues a delegated call of the form:delegate(@secondObject.suspend()).
An Implementation of The Hybrid Concurrency Model30
This suspends the calling activity until a call toresume opens the delay queue. Assuspend is
called by a delegated call the calling object is free to accept further calls before the call to sus-
pend returns. A call toresume opens the delay queue and so that the call tosuspend may be pro-
cessed and the invoking thread resumed. The resumed thread closes the delay queue so that the
next call tosuspend will also be delayed. This example assumes thatresume is called only when
there is a delayed call. If not, the delay queue would remain open and the next call tosuspend
would not be delayed.
2.3 An Implementation of The Hybrid Concurrency Model
For the implementation of the Hybrid prototype [42] we developed,on top of Unix, a runtime
environment to better support the needs of the system. This runtime environment which provides
support for concurrency, persistence and communication with the outside world is implemented
as a single Unix process. Concurrency is supported by a “custom made” package for lightweight
processes which share the address space of this Unix process. Persistence is provided as in the
Smalltalk-80 system by saving the workspace of active objects to a file. The size of the work-
space is limited to the size of virtual memory. Communication to the outside world is provided
by an i/o package based on Unix sockets. This i/o package is integrated with the lightweight
package in the sense that i/o requests block only the requesting lightweight process and multiple
“virtual” connections are supported over a single socket.
Figure 2.2 shows the system’s architecture. The basic system components are the work-
space manager, the type manager and the activity-domain manager. The workspace manager
maintains a persistent workspace for storing objects. The type manager maintains information
about object types. The activity-domain manager keeps track of the state of execution of Hybrid
domains and activities.
The Hybrid compiler translates object type definitions to C code that uses the functionality
of the runtime environment. The compiler interacts with the type manager for finding out infor-
mation about existing types and for storing information about new types. The generated C code
includes calls to functions that provide the interface to the basic system components of the runt-
ime environment. Thus, Hybrid objects, by being translated into C, are integrated and use the
services of the runtime environment.
A limitation of the current implementation is that it is not possible to compile and integrate
new classes to the system while it is running. This could be made possible by a dynamic linking
Chapter 2 31
facility that would allow the C code produced by the Hybrid compiler to be read in and dynam-
ically linked with the runtime environment.
Multiple users may interact with the system, as shown in figure 2.3, through processes that
connect as clients to the runtime environment process which acts as a Hybrid server. Client pro-
cesses are responsible for implementing user interaction objects, such as windows, for which
shadow versions exist in the runtime environment..
In the following sections we are going to describe how the message-passing concurrency
model of Hybrid was implemented in the “shared memory” runtime environment described
above. A more detailed presentation of the prototype implementation may be found in [42].
Figure 2.2 System architecture
Runtime Environment
I/OLibrary
LightWeightProcesses
PersistentWorkspace
Activity/
Manager
PredefinedObjectLibrary
TypeManager
WorkspaceManagerDomain
Basic System Components
Hybrid Objects
Runtime Library Hybrid Compiler
SystemObjects
Figure 2.3 Multi-user support
HybridObjects
SystemDefinedObjects
I/OLibrary
User InteractionObjects
I/O Library
User InteractionObjects
I/O Library
Client Process Hybrid Server Client Process
Socket Socket
An Implementation of The Hybrid Concurrency Model32
2.3.1 Implementing the Concurrency Model
Although in Hybrid all objects are considered as active entities that resemble processes that in-
teract by exchanging messages, they are implemented as passive data types whose operations
are invoked by the lightweight processes of the runtime environment. The execution of the ob-
ject’s operations by the lightweight processes is appropriately synchronized so as to reproduce
the semantics of Hybrid’s model of active objects.
We found this approach for the implementation of Hybrid to be natural as:
• The runtime environment that we built for supporting the language provided a shared
memory architecture, i.e. lightweight processes sharing the address space of a Unix pro-
cess.
• Operation oriented languages like Hybrid, which use remote procedure call as their main
object interaction mechanism can be implemented efficiently as a procedure oriented
language in a shared memory environment[9].
Another approach to the implementation of the prototype would have been to use Unix processes
to support concurrency and build a run time environment based on a “distributed architecture,”
that is the logically distributed address spaces of Unix1 processes communicating through sock-
ets. This, however, would not eliminate the need to support concurrency within a Unix process
as delegated calls require quasi-concurrent execution within Hybrid objects. Moreover, it would
force us to resolve issues concerning the distributed execution of Hybrid which we did not want
to consider for the implementation of the prototype.
2.3.2 Efficiently Supporting the Active View of Objects
The run-time overhead induced by the active view of objects in the above implementation is due
to the synchronization of method execution. As objects of any type may be invoked concurrently
it may seem that synchronization code has to be generated in the methods of all objects to control
their concurrent invocation. In fact, the synchronization takes place when objects are invoked,
rather than by code generated within methods. The use of different kinds of references for ob-
jects makes it possible to synchronize only the invocations of objects whose methods may be
invoked concurrently.
The predefined object type,oid, is used for specifying a reference to an object. Oids may be
passed around to other objects so that the methods of an object having an oid may be invoked
1. The implementation platform was a 3.2 Sun operating system; a 4.3BSD based system which did not
provide lightweight processes or shared memory facilities. The main ipc mechanism provided was sockets.
Chapter 2 33
concurrently. On the other hand, objects that are addressed by instance variable names are local
to the enclosing object and are not known to other objects so their methods may not be invoked
concurrently. As objects that are addressed by instance variable names may not be addressed by
oids and conversely, only invocations through oids need to be synchronized.
The use of the type oid is illustrated below in the definition of a typeA with a method
anAMethod. Instances of this type have two instance variables, local andshared, for referencing
two objects of a typeB. The object stored inlocal may only be addressed through this name and
thus it may not be known outside the scope of the containing object of typeA. Variableshared
stores an oid that is used to refer to another object of typeB. The oid may be known to other
objects, consequently invocations of objects addressed by oids, [email protected], are syn-
chronized. No synchronization occurs when invoking methods of objects that are addressed by
local names, as inlocal.aBMethod().
type A: abstract {
anAMethod: ->;
} ;
private{
var local: B;var shared: oid of B;
anAMethod: -> ;
{
...local.aBMethod(); @shared.aBMethod(); ..
}
}
2.4 The Integration of the Concurrency and Object-Oriented Features
In the preceding sections we have presented how object-oriented and concurrency features have
been combined in Hybrid. We have also discussed and shown that the concurrency constructs
successfully address the main issues underlying concurrent programming. The further study of
the language reveals several deficiencies in its support for object-oriented software development
that are due to the interference of concurrency and object-oriented features. These are revealed
by the difficulties in using or taking full advantage of the object-oriented features for program-
ming concurrent objects. More specifically we will discuss the following issues concerning the
integration of concurrency and object-oriented programming that came out in our experience
with Hybrid:
• Encapsulation and intra-object concurrency. Hybrid adopts an active object model where do-
mains are the units of concurrent execution. This approach protects, by default, objects from
concurrent invocation of their operations. This extends the protection of the internal state of
The Integration of the Concurrency and Object-Oriented Features34
objects provided by encapsulation to encompass concurrency. However, with this approach
objects cannot be internally concurrent. As we discuss below this choice affects the support
for data abstraction. It is essential for a COOPL to support data abstractions that use internal
concurrency for servicing requests.
• Combining synchronization with class inheritance. Although Hybrid supports multiple inher-
itance it is difficult to take advantage of inheritance when classes make use of delay queues.
• Constructing data abstractions with concurrent implementations. It should be possible, when
desirable, to hide from the clients of an object, implementation decisions such as scheduling
and concurrently processing of requests. In Hybrid this is not always possible because of the
semantics of delegated calls.
2.4.1 Encapsulation and Intra-Object Concurrency
The approach taken in Hybrid to consider domains as the units of parallel execution provides a
synchronization boundary that is coarser than the encapsulation boundary provided by objects.
A domain consists of at least one object and its subobjects which are encapsulated within it and
possibly other, explicitly created, objects whose existence is not confined by the enclosing ob-
ject. Domains provide, by default, mutual exclusion at the object level which protects objects
from concurrent invocations.
Mutual exclusion at the object level adequately extends encapsulation and data abstraction
supported by objects to encompass concurrency. The integrity of an object’s state is protected
from the hazards of concurrent invocation of its methods which share its state. Mutual exclusion
is provided by default so one does not have to impose it as a requirement on the object’s imple-
mentation.
The fact that domains and consequently objects are the unit of concurrency does not permit
intra-object concurrency. In order to implement an object that uses concurrency for increased
throughput intra-object concurrency has to be simulated by a collection of independent objects
capable of concurrent execution that cooperate to implement the intended functionality. One of
these objects provides the interface to clients of the collection hiding the fact that a collection of
concurrent objects rather than a single object is used for implementing its services.
The implementation of an object as a collection of concurrently executing objects may
however present some difficulties.
• It may be difficult to abstract from the fact that the object is implemented by a collection of
objects. This happens in Hybrid as we discuss in 2.4.3. when delegated calls are used for im-
Chapter 2 35
plementing objects concurrently. Delegated calls cause the caller’s domain to become idle.
This may cause a message to be accepted by other objects in the domain which may not be in
a state appropriate for accepting the message. In order to prevent this effect, objects whose
implementations make delegated calls should be created as separate domains.
• Depending on the constructs provided for object interaction the decomposition of an object
into a collection of interacting objects may be complex and present substantial overhead due
to the number of messages exchanged between components. Here the decomposition is car-
ried out to take advantage of potential concurrency among objects rather than to represent sep-
arate entities. The encapsulation that is provided by objects may work against us because the
object’s state is partitioned to provide concurrent execution.
The issue of protecting an object’s state from concurrent execution is important but it is not a
reason for not supporting or overlooking intra-object concurrency. Objects can be protected
from external concurrency by synchronizing invocation without forcing them to be internally se-
quential. However, if a language takes the approach to support concurrent implementations by
a collection of interacting objects, special attention should be paid in the design of its concur-
rency constructs so that it is possible for a collection of cooperating objects to be equivalent, in
some sense, to a single object.
2.4.2 Combining Synchronization and Inheritance
The main problem for supporting inheritance in a COOPL is to combine the synchronization
constraints of the inherited methods with those of the new methods defined in a subclass and, at
the same time, support some encapsulation between classes and their subclasses. These difficul-
ties arise in several object-oriented languages [3][27][41][69]. Here, we present the problem as
it occurs in Hybrid. In chapters 3 and 4 we will examine more language designs and we are also
going to discuss some promising approaches[41][80].
The synchronization constraints on the execution of an object’s operations are expressed in
Hybrid by using delay queues. In order to synchronize the execution of an operation with the
object’s state the operation is associated with a delay queue. The delay queue should be open or
closed respectively for the object’s states in which the operation’s execution may or may not
take place. The operations that modify the object state should take care to open and close the
delay queues according to the resulting state. This way of synchronizing operation execution, by
opening and closing delay queues, presents two difficulties when combined with class inherit-
ance:
The Integration of the Concurrency and Object-Oriented Features36
• It may be necessary to redefine the inherited methods: The new methods defined by a subclass
may need to synchronize their execution with the object’s state. To achieve this synchroniza-
tion new delay queues may need to be defined by the subclass and be associated with the new
methods. The trouble is that inherited methods may modify the objects state in a way that re-
quires some of the delay queues defined by the subclass to be opened or closed. This eventu-
ality makes it necessary to examine the modifications performed by inherited methods to the
object’s state and to redefine those that should open or close some delay queues. Moreover,
the examination of the inherited methods is not restricted to methods of the parent class but
extends to all ancestor classes whose methods may modify the object’s state.
• It is difficult to support encapsulation among subclasses and parent classes: Delay queues are
defined as instance variables of type delay. In order to open and close the delay queues asso-
ciated with the methods of the parent class, the methods of the subclass access the implemen-
tation of the parent class. This violates the encapsulation of object classes [75] causing unde-
sirable dependencies between the internal representation of classes and their superclasses.
2.4.3 Data Abstractions with Concurrent Implementations
One of the benefits of data abstraction provided by objects is that it separates the issues concern-
ing what “services” are provided at an object’s interface from the way that they are implemented.
This separation of concerns encourages the development of systems that are open in respect to
refinements and extensions brought to objects as long as they present upward compatible inter-
faces.
This separation of interface and implementation for COOPLs would mean that different
implementations of objects could define different policies for scheduling requests, processing
requests in parallel or using internal parallelism for increased throughput. For instance, a disk
head scheduler object could use a variety of scheduling policies [77] in its implementation. As
another example, consider a symbol table object. It could be implemented sequentially forcing
all requests to be executed one after the other, or it could service requests in parallel by imple-
menting a readers-writers [23] scheduling scheme.
The implementation of objects that service requests in parallel and the implementation of
general request scheduling policies are achieved in Hybrid as shown in 2.2.2 and 2.2.3 by using
the delegated call mechanism. In the design of the concurrency constructs, considering concur-
rency and data abstraction to be orthogonal, not much attention was paid to support of delegated
calls for data abstraction. It turned out by further experience with the language that special care
has to be taken for using objects whose implementations make use of delegated calls and for re-
Chapter 2 37
placing an object implementation by one that makes use of this mechanism. This makes it nec-
essary to be aware of the use of gelegated calls and constrains the implementation of objects.
Thus, it diminishes the benefits of data abstraction.
Consider an objectA which calls a method of another objectB which is in the same domain.
If B issues a delegated call its domain becomes idle and objects in the domain may accept further
call or return messages.Thus, the delegated call inB may trigger the execution of a method of
any object of the domain because of the acceptance of a pending call message. In particular, it
may trigger the execution of another method ofA. This causes an interleaved execution ofA’s
methods as the execution of the method that invokedB in the first place is not yet completed.
This interleaved execution occurs in points that are not controlled byA but may cause the exe-
cution ofA’s method to fail. The class invariant, which is a necessary precondition for the correct
execution ofA’s methods[37][54], may not hold whenA callsB or any other object.
This problem may be circumvented by an appropriate implementation ofA that takes into
account the fact that delegated calls take place withinB. It is possible to implementA in such a
way that the class invariant is satisfied before callingB’s methods or to prevent the activation of
otherA’s methods by using delay queues or by havingA andB be in separate domains. These
solutions, which are inconvenient, rely on the fact that it is known thatB’s implementation uses
delegated calls. It would be unrealistic to require that the class invariant hold before calling any
other object or to implement every object called by A as a separate domain to foresee the even-
tuality of delegated calls.
The ways, mentioned above, to cicumvent the problem with delegated calls are contrary to
data abstraction, since it is necessary to know how an object is implemented in order to construct
correct programs. Furthermore, it is not possible to safely replace the implementation of an ob-
ject that doesn’t use delegated calls by one that does without re-examining all the programs that
were based on the old implementation.
2.5 Summary
Hybrid served as a concrete example showing that the successful integration of concurrency and
object-oriented programming requires a lot more than a syntactic integration of the concurrency
constructs with object-oriented features. Moreover, the examination of Hybrid’s features al-
lowed us to gain more insight into the general issues underlying the design of concurrent object-
oriented languages and the integration of concurrency and object-oriented programming.
Summary38
• The active view of objects is appropriate for supporting encapsulation and protecting the
internal state of objects from concurrent invocations and makes it possible to reuse ob-
jects in concurrent applications. The approach taken for implementing Hybrid shows that
this view of objects can be supported without having to implement all objects as process-
es which would be unrealistic in systems where context switching and inter-process
communications are a lot more expensive than procedure calls.
• Synchronization of method execution interferes with class inheritance and encapsula-
tion. As it is the case with delay queues, method synchronization should not be specified
in terms of the instance variables of objects. Such an approach makes it necessary to vi-
olate encapsulation in order to synchronize the execution of methods of a class with those
of its superclass and it may also be necessary to redefine the inherited methods.
• Scheduling of requests by objects and concurrent implementations of objects should be
supported in a way that is consistent with data abstraction. Although the concurrency
constructs of Hybrid are satisfactory for request scheduling and for concurrent imple-
mentations they do not adequately support data abstraction. In general for request sched-
uling and for concurrent implementations it is needed to use several objects and delegat-
ed calls. However, objects that are implemented by using delegated calls are not, in gen-
eral, substitutable with those that do not, despite the fact that they may present the same
interface and provide the same services to their clients.
It is important to note that the deficiencies of Hybrid’s concurrency constructs for support-
ing an object-oriented programming style that promotes reuse were uncovered by constructing
appropriate examples, or rather counter-examples. These illustrated situations where the design
of the language features made it difficult to take advantage of object-oriented techniques such
as data abstraction and inheritance. In order to be more confident about the support for OO pro-
gramming provided by the other design alternatives that we examine in chapter 3, we would like
to develop more systematic ways for evaluating and comparing language features with respect
to their support for OO programming. Along this direction in chapter 4 we develop a list of in-
formal requirements that we use for comparing the design alternatives discussed in chapter 3.
Also, the semantic framework for describing the semantics of COOPL features, developed in
chapter 5, is, as we discuss in chapter 6, a step towards a more rigorous approach for examining
the interaction and evaluating the integration of object-oriented and concurrency features.
CHAPTER 3
A Design Space for ConcurrentOOPLs
A large number of concurrent object-oriented languages have been designed and implement-
ed[69]. These languages vary considerably in the design of their concurrency features and in the
way that they are combined with the object-oriented features. The various design choices taken
in these languages are not equally successful in integrating concurrency and object-oriented fea-
tures, and consequently, for taking advantage of object-oriented techniques and their software
reuse potential in the construction of concurrent software.
A language may support features characterizing it as object-oriented [87] as well as con-
currency constructs that successfully address the main issues underlying concurrent program-
ming [9]. However, the concurrency features may interfere with the object-oriented features pre-
venting the latter to fullfil their purpose and effectively support object-oriented programming
techniques. The presentation of Hybrid in chapter 2 showed how this interference may occur in
several aspects of the design of a language.
In order to understand what are the essentially different design choices with respect to their
support for object-oriented programming we construct a language design space that expresses
these choices in terms of the relationship between objects and concurrency. This design space is
used in next chapter for evaluating the support for object-oriented programming achieved by de-
sign alternatives.
We start by presenting three aspects of COOPLs that we consider for constructing the de-
sign space. Then we discuss the design choices which respect to each of these aspects. In section
3.5 we examine more closely some existing languages showing how the design of their features
40 A Design Space for Concurrent OOPLs
situate them in the design space. We finally summarize by presenting a number of tables dis-
playing how the surveyed languages’ features are classified in terms of the design space. We also
discuss some cases where the reasons for classifying a language’s feature in a certain way may
not be obvious.
3.1 A Design Space for Concurrent OOPLs
We seek to evaluate language design choices with respect to the integration of their concurrency
and object-oriented features and the degree to which software reuse is supported. In particular,
we wish to understand how choices of concurrency constructs interact with object-oriented tech-
niques and affect the reusability of objects. As such, our classification scheme concentrates on
the relationship between objects and concurrency. We shall consider the following aspects:
• Object Models: how is object consistency maintained in the presence of concurrency?
The way objects are considered with respect to concurrent execution may or may not pro-
vide them with a default protection with respect to concurrent invocations.
• Internal Concurrency: can objects manage multiple internal threads? This issue con-
cerns the expressive power that is provided to objects for handling requests. The execu-
tion internal threads is also related to the protection of the internal state objects. This is,
however, a separate issue that is addressed by the choice of the object model discussed
above.
• Constructs for Object Interaction: how much freedom and control do objects have in
sending and receiving requests and replies? The choice of concurrency constructs for
sending and receiving messages determines the expressive power that is provided for im-
plementing concurrent objects. Moreover, the design of constructs for conditional accep-
tance of messages interacts with the use of class inheritance.
In the presentation of the design space, it will become apparent that these aspects are not entirely
independent: certain combinations of choices are contradictory and others are redundant or lack
expressive power.
3.2 Concurrent Object Models
We shall first consider whether or not objects are provided with a default means of protecting
internal consistency in the presence of concurrent requests. There are three main approaches:
Chapter 3 41
• The Orthogonal Approach:Concurrent execution is independent of objects. Synchronization
constructs such as semaphores in Smalltalk-80 [34], “lock blocks” as in Trellis/Owl [60] or
monitors as in Emerald[14] must be judiciously used for synchronizing concurrent invoca-
tions of object methods. In the absence of explicit synchronization, objects are subject to the
activation of concurrent requests and their consistency may be violated.
• The Homogeneous Approach:All objects are considered to be “active” entities that have
control over concurrent invocations. The receipt of request messages is delayed until the ob-
ject is ready to service the request. There is a variety of constructs that can be used by an ob-
ject to indicate what method invocation it is willing to accept next. In POOL-T [5]this is spec-
ified by executing an explicit accept statement. In Rosette [80]anenabled set is used for spec-
ifying which set of messages the object is willing to accept next.
• The Heterogenous Approach: Both active and passive objects are provided. Passive objects
do not synchronize concurrent requests. Examples of such languages are Eiffel //[54][21] and
ACT++ [41]. Both languages ensure that passive objects cannot be invoked concurrently by
requiring that they be used only locally within single-threaded active objects.
Although most COOPLs fall clearly within one of these three categories, there are a number of
limit cases. For example, Argus[51] appears to support a heterogeneous model since it provides
bothguardians (active objects) and CLU [48]clusters (passive objects), but the synchronization
of multiple threads within guardians corresponds to the orthogonal model.
3.3 Internal Concurrency
Wegner [87] classifies concurrent object-based languages according to whether objects are in-
ternally sequential, quasi-concurrent or concurrent:
• Sequential Objectspossess a single active thread of control. Objects in ABCL/1[92] and
POOL-T and Ada tasks [8] are examples of sequential objects.
• Quasi-Concurrent Objects have multiple threads but only one thread may be active at a time.
Control must be explicitly released to allow interleaving of threads. Hybrid domains[62] and
monitors[38] are examples of such objects.
• Concurrent Objects do not restrict the number of internal threads. New threads are created
freely when accepting requests. Adapackages and POOL-Tunits resemble concurrent objects
(though they are not first class objects). Languages like Smalltalk-80 that adopt the orthogonal
42 Internal Concurrency
object model also support concurrent objects in the sense that a new local thread is effectively
created whenever a method is activated in response to a message.
According to the above classification, the threads of concurrent objects are created freely
when a message arrives to an object. However, there are languages where objects may have in-
ternally y concurrent threads that are not freely created by message reception. In order to include
these languages in the classification and to capture more information about the way that threads
are created, we generalize the concurrent object class to include any language in which objects
have concurrent threads, irrespective of the way they are created, and consider separately the is-
sue of thread creation.
We define three, non-exclusive, ways for the creation of threads within objects as follows:
• By message reception: Thread creation is triggered by reception of a message. Depending on
whether objects may control the creation of threads we have the following sub-categories:
• Controlled by the object:The object may delay the creation of threads. For example, in
the language SINA [81] a new concurrent thread may be created for the execution of a
method belonging to a select subset of the object’s methods only if the currently active
thread executes thedetach primitive.
• Unconstrained creation:Threads are created automatically at message reception. This is
the default for languages with an orthogonal object model.
• Explicit creation: Thread creation is not triggered by message reception but by the execution
of some construct by the object. For instance, in SR [10] there is a construct similar to a “cobe-
gin“[9] to initiate the execution of concurrent threads
Thenext andbecome primitives in Rosette and ACT++ can be viewed as a controlled cre-
ation of threads, with the additional restriction that concurrent threads may not share the object’s
state since they execute on different “versions” of the object.
Internal Concurrency
SEQUENTIAL
Single thread of control
ABCL/1, POOL-T
QUASI-CONCURRENT
There are several logical threads butonly one at a time. Thread interleavingoccurs at programmer defined places
Hybrid, monitors
CONCURRENT
There may be several threads ofcontrol active within an object.
Chapter 3 43
In Guide [43], an object may be associated with a set of activation conditions that specify
which methods may be executed in parallel by internally concurrent threads. In the default case,
as with any language following an orthogonal approach for concurrency, objects may be viewed
as concurrent with unconstrained creation of threads triggered by external messages.
The creation of threads by reception of external messages or by execution of a special con-
struct are neither mutually exclusive design choices, as illustrated by SR which supports both,
nor redundant as we will find out in the next chapter.
3.4 Constructs for Object Interaction
We classify these constructs with respect to the degree of control that can be exercised by objects
in the client and server roles. We specifically considerreply scheduling, which concerns the de-
gree of flexibility the client has in accepting a reply, andrequest scheduling, which concerns the
control the server can exercise in accepting a request.
3.4.1 The Client’s View - Issuing Requests
From the client’s point of view, there are three important issues concerning the constructs sup-
ported for issuing requests:
• Interleaving activities: Can the current thread continue after issuing the request?
• Reply address: How and where is the reply to be sent? Flexible control over the reply desti-
nation can reduce the amount of message passing required.
• Getting the reply: What mechanisms are supported for matching replies to requests? How
does the client synchronize itself with the computation and delivery of the reply?
We initially distinguish betweenone-way message passing communication primitives and con-
structs supporting arequest/reply protocol. The latter provide support for object interactions
Thread Creation
BY MESSAGE RECEPTION EXPLICIT CREATION
SR co, Smalltalk-80 fork
UNCONSTRAINTEDCREATION OF THREADS
⇒ORTHOGONAL OBJECT MODEL
Smalltalk-80, Ada packages
CREATION OF THREADS ISCONTROLLED BY THE OBJECT
SINA, Act++
44 Constructs for Object Interaction
where requests will be eventually matched by replies. These primitives vary in the flexibility in
sending requests and receiving replies. Strict rpc approaches enforce that requests will be
matched by a reply and delay the calling thread until the reply is available. Further flexibility is
provided by “proxy” objects which disassociate the sending or receiving of messages from the
current thread of control. Examples of build-in proxy objects arefuture variables[92] andCBox-
es[90].
One-way Message Passing
Whether communication is synchronous, as in CSP[39] or PROCOL [84], or asynchronous, as
in actor languages, clients are free to interleave activities while there are pending requests. Sim-
ilarly, replies can be directed to arbitrary addresses since the delivery of replies must be explic-
itly programmed.
The main difficulty with one-way message passing is getting the replies. The client and the
server must cooperate to match replies to requests. As we shall see in chapter 4, the additional
flexibility and control provided by one-way message passing over request/reply based approach-
es can only be properly exploited if objects (i.e., servers) are implemented in such a way that the
reply destination can always be explicitly specified in a request.
Remote Procedure Call
With RPC the calling thread of the client is blocked until the server accepts the request, performs
the requested service and returns a reply. Most object-oriented languages support this form of
interaction, though “message passing” is generally compiled into procedure calls.
Supporting RPC as the only means for object interaction may be a disadvantage when ob-
jects are sequential as we will see in the next chapter. Although it is trivial to obtain a reply, it
is not possible to interleave activities or to specify reply addresses.
Client/Server Interaction
ONE-WAY MESSAGE PASSING
Higher-level protocols must be ex-plicitly programmed
PROCOL, CSP
REQUEST/REPLY
Balanced requests andreplies are supported.
PROXIES
Sending requests and receiving replies maybe delegated, as with CBoxes andfutures
ABCL/1, ConcurrentSmalltalk, Eiffel //
RPC
Sending a request blocks thecurrent thread until a reply isreceived.
Chapter 3 45
Proxies
An alternative means which provides the client with more flexibility in sending and receiving
replies is to introduceproxies. The main idea is to delegate the responsibility of delivering the
request and obtaining the reply to a proxy. (The proxy need not be a first-class object, as is the
case withfuture variables [92].) The actual client is therefore free to switch its attention to an-
other activity in the mean time. The proxy itself may also perform additional computation or call
multiple servers.
If necessary, the reply is obtained by the original client by an ordinary (blocking) request.
This approach, variants of which are supported by several languages [21][92][90], maintains the
benefits of an RPC interface and the flexibility of one-way message passing. In contrast to one-
way message passing, however, there is no difficulty in matching replies to requests.
A closely related approach is to combine RPC with one-way message passing. In ABCL/1,
for example, an object that externally has an RPC interface may internally use lower level mes-
sage passing primitives to reply by sending an asynchronous message to the client or to its proxy.
The use of such facilities is further discussed in chapter 4.
3.4.2 The Server’s View - Constructs for Accepting Requests
A main concern from the point of view of an object acting as a server is whether requests can be
conditionally accepted1. When a request arrives the server may be busy servicing a previous re-
quest, waiting itself for another request to be fulfilled, or idle, but in a state that requires certain
requests to be delayed. We distinguish initially between conditional and unconditional accep-
tance of requests. Conditional acceptance can be further discriminated according to whether re-
quests are scheduled by an explicit acceptance, by activation conditions or by means of reflec-
tive computation:
Unconditional acceptance
Unconditional acceptance of requests is illustrated by monitors[38] and by Smalltalk-80 [34]
objects. The mutual exclusion that is provided by monitors could be considered as an implicit
condition for the acceptance of requests. However, the mutual exclusion property is captured by
viewing monitors as quasi-concurrent objects so we consider request acceptance to be uncondi-
1. A secondary issue is whether further activity related to a request may continue after the reply has been
sent as in the Send/Receive/Reply model [32], but this can also be seen as concern of internal concurrency
where follow-up activity is viewed as belonging to a new thread.
46 Constructs for Object Interaction
tional. Note that message acceptance for languages with an orthogonal object model is by default
unconditional.
Explicit acceptance
With explicit acceptance, requests are scheduled by means of an explicit “accept” statement ex-
ecuted in the body of the server. Accept statements vary in their power to specify which messag-
es to accept next. Acceptance may be based on message contents (i.e., operation name and argu-
ments) as well as the object’s state. Languages that use this approach are Ada, ABCL/1, Con-
current C, Eiffel //, POOL-T and SR. With this approach objects are typically single-threaded,
though SR is an exception to this rule.
Activation conditions
With activation conditions, requests are accepted on the basis of a predicate over the object’s
state and, possibly, the message contents. The activation condition may be partly implicit, such
as the precondition that there be no other threads currently active within the object. An important
issue is whether the conditions are expressed directly on a particular representation of the ob-
ject’s state or if they are expressed in more abstract terms. In Guide, for example, each method
Request Scheduling
UNCONDITIONAL
No Synchronization withthe state of the target
ADA packets, Smalltalk-80, Emerald, Trellis/Owl.
EXPLICIT ACCEPTANCE
The execution of the opera-tion is synchronized with an“accept” statement explicitlyexecuted by the target.
ADA tasks, ABCL/1, SRPOOL-T, Eiffel//.
ACTIVATION CONDITIONS
Explicit or implicit conditions onthe target’s state determine whenthe execution of an operation maytake place.
The arrival of a message at the targettriggers a reflective computation in theassociated meta-object. This determineswhether the requested operation shouldbe executed.
ABCL/R, ACTALK
REFLECTIVE COMPUTATION
ABSTRACT –REPRESENTATIONSPECIFIC
REPRESENTATIONINDEPENDENT
Conditions are expressed in terms of ab-stract properties of the object and do notrefer to the particular implementation
ACT++, ROSETTE, PROCOL,PATH EXPRESSIONS
Condition are expressed directlyon the hidden object state.
GUIDE, Hybrid, SINA
ACCEPTANCE CONDITIONALACCEPTANCE
Chapter 3 47
is associated with a condition that references the object’s instance variables, whereas in ACT++
the condition for accepting a message is that the object be in an appropriateabstract state which
abstracts from the state of a particular implementation. Another approach is to specify the legal
sequences of message acceptance by means of a regular expression, as in path expressions[19]
and PROCOL [84].
Reflective computation
With reflective computation the arrival of a request triggers a method of the server’smeta-ob-
ject. The meta-object directly then manipulates object-level messages and mailboxes as objects.
This approach is followed by the language ABCL/R [86] and it is also illustrated in Actalk[18]
where some reflective facilities of the Smalltalk-80 system are used to intercept messages sent
to an object and synchronize their execution in a way that simulates message execution in actor-
based languages.
3.5 Classification of Existing Languages
3.5.1 The Orthogonal Approach
Smalltalk-80
Smalltalk-80 [34] supports concurrent programming by processes that communicate through
shared objects. The creation of processes is accomplished by sending a fork message to a block
context and semaphores are provided for their synchronization and mutual exclusion.
The object model is orthogonal to concurrent execution. The protection of objects from
concurrent execution is ensured by judicious use of semaphores. This can be done in two ways.
Either the calling process uses semaphores before invoking operations on shared objects or the
execution of an object’s operations is synchronized by using semaphores in its implementation.
As we see later both these ways interfere with support for object reuse and with class inheritance.
The objects may be classified as internally concurrent since several threads may execute
concurrently within an object. The execution of threads in a Smalltalk-80 system is essentially
quasi-concurrent as the active thread has to explicitly give up the “cpu.” However, objects do
not have full, local control over the quasi-concurrent thread execution.The suspension of the cur-
rent thread and the activation of another may take place in some other object. For this reason we
view objects as being internally concurrent.
48 Classification of Existing Languages
The creation of threads may be initiated either by messages sent to the objects or by the ob-
ject itself by sending a fork message to a local block. The creation of threads by reception of
messages is not controlled by the object.
Object interaction may be characterized as following a remote procedure call model where
a new thread is created automatically for handling calls in the called object. There are no con-
structs for expressing conditional acceptance of messages. This has to be programmed by sus-
pending, through the use of a semaphore, the threads created for executing methods that cannot
be processed in the current object’s state.
It is interesting to note that some reflective facilities of the Smalltalk system may be used
to easily accommodate different object models and object interaction constructs[17][73]. The
approaches are based on a facility that is provided in Smalltalk for error handling. This allows
the reception of a message to intercepted and triggers the execution of a method to which the
message is provided as an argument. This method may decide to execute or delay the execution
of the requested method according to the simulated object model. Furthermore, as in Smalltalk
blocks are first class objects, various approaches for conditional acceptance may be nicely pack-
aged as constructs.
Emerald
Emerald [14] is an object-oriented language for programming distributed applications. An ob-
ject may be associated with a process that starts executing after the object has been created and
initialized.
The operations of objects may be invoked concurrently by their own process, if they have
one, and by those of other objects. Synchronization of processes and mutual exclusion is accom-
plished by using monitors [38]. A number of monitors may be used in the implementation of ob-
jects and their operations may be implemented as monitor procedures. This approach is more
flexible than viewing the whole object as a single monitor since it allows operations that are not
implemented as monitor procedures or that are in different monitors to execute in parallel.
The orthogonal approach is followed for the object model. Objects are not protected from
concurrent execution unless monitors are used in their implementation.
Objects are internally concurrent. The creation of threads within objects, apart from the
thread that may declared within the object, is triggered by external messages and cannot be ini-
tiated by the object itself. If an object needs to create a new internal thread it has to create a new
Chapter 3 49
object that will invoke one of its operations. Remote procedure call is used for object communi-
cation and no constructs are provided for conditional acceptance of requests.
Trellis/Owl
Trellis/Owl [60] supports concurrent execution by explicit creation of concurrent threads called
activities for the execution of an operation. Activities may be created for the execution of any
operation and they communicate by invoking the operations of shared objects. The language de-
fined typeslock andwait queue are provided to support synchronization and mutual exclusion.
Objects of these types may be defined as instance variables of an object. Mutual exclusion is
achieved by associating code blocks with locks. Combinations oflock blocks, blocks associated
with locks, and wait queues may be used for implementing objects similar to monitors, yet they
allow more flexibility than monitors, since some operations may be allowed to execute concur-
rently.
There is also support for direct synchronization of activities. An activity may wait until
some other activity terminates. A typeActivity_Set is also providedfor allowing an activity to
wait until one or all of the activities in the set terminates.
Figure 3.1 illustrates the use of locks and wait queues in the implementation of a character
buffer of unbounded size that may be shared by concurrently executing activities.
The orthogonal approach is taken for the object model as no default protection of objects is
provided. Objects are internally concurrent. Concurrent threads may be created either by the re-
ception of messages or by the object by creating a new activity for the execution of some oper-
ation. Object interaction takes the form of remote procedure calls and acceptance of requests is
unconditional.
Guide
In Guide [43] threads, called activities, communicate by calling the operations of shared passive
objects. The synchronization mechanism consists of associating anactivation condition with the
object’s operations which must be true before the execution of an operation may take place. Ac-
tivation conditions are boolean expressions that may refer to arguments of the invoked opera-
tion, instance variables, a number ofsynchronization counters and operation names. Synchroni-
zation counters are associated with an operation and record automatically the number of started,
completed, pending and ongoing executions of an operation. For instancestarted(op) is the num-
50 Classification of Existing Languages
ber of initiated execution of operationop, completed(op) is the number of terminated executions
of op andcurrent(op) is equivalent tostarted(op) - completed(op). Some keywords are used as
syntactic sugar for commonly used activation conditions. For instance the keyword EXCLU-
SIVE may be used in the activation condition of an operation for expressing mutual exclusion.
The same thing can also be done by having an activation condition stating that the sum ofcur-
rent(op) over all operationsop of the object must be equal to zero. The keyword NOT followed
by the name of an operation specifies that there cannot be any ongoing executions of the speci-
fied operation.
Figure 3.2 illustrates the use of activation conditions in the implementation of a bounded
buffer in Guide. TheCONTROL clause specifies the activation conditions for the operationsGet
andPut. The term “NOT Get AND NOT Put” specifies mutual exclusion of both operations. Re-
placing this term by the keywordEXCLUSIVE would have the same effect. The term “nbr < size”
Figure 3.1 Lock blocks in Trellis/Owl
type_module Shared_char_Buffer
component me.mutex : Lock;component me.nonempty : Wait_Queue;component me.buffer : Char_Queue;
operation create (Mytype) returns (Mytype)is allocatebegin
me.mutex := create(Lock);me.nonemoty := create(Wait_Queue);me.buffer := create(Char_queue);
end;
operation insert(me, x: Char)is begin
lock me.mutex doinsert(me.buffer,x);wakeup(me.nonempty);
end lock;end;
operation remove (me) returns (Char)is begin
lock me.mutex doif( empty(me.buffer)) then
wait(me.nonempty)end if;return remove (me.buffer);
end lock;end;
end type_module;
Chapter 3 51
in the activation condition forPut prevents the execution ofPut when the buffer is full. Similarly
nbr > 0 prevents the execution ofGet when the buffer is empty. The code of the operationsPut
andGet does not include any synchronization primitives.
Guide takes also an orthogonal approach for its object model as, by default, objects are not
protected from concurrent execution. Object are internally concurrent.Thread creation is trig-
gered either by reception of messages or by the execution of acobegin statement used for creat-
ing new activities. Object interaction takes the form of remote procedure calls. Conditional ac-
ceptance of requests is expressed by activation conditions that depend on the object’s internal
state.
ConcurrentSmalltalk
ConcurrentSmalltalk [90]is an extension of Smalltalk-80. The aims in the design of this lan-
guage were to provide a better integration of concurrent programming with objects than is the
case with processes and semaphores in Smalltalk-80.
Figure 3.2 Activation conditions in Guide
TYPE boundedBuffer ISMETHOD Put(IN i: Item);METHOD Get(OUT i: Item);
END boundedBuffer
CLASS FixedSizeBuffer ISIMPLEMENTS boundedBuffer;
CONST size = some constantbuffer: ARRAY[0..size-1] of Item;nbr , first, last: Integer = 0, 0, 0;
METHOD Put( IN i: ITEM );BEGIN
...code for put...END Put;
METHOD Get( OUT i: Item );BEGIN
...code for get...END Get;
CONTROLPut: NOT Get AND NOT Put AND nbr < size;Get: NOT Get AND NOT Put AND nbr > 0
52 Classification of Existing Languages
The concurrent features introduced are: asynchronous method invocation, allowing meth-
ods execution to proceed after returning a result, Cbox objects for synchronization, and anatom-
ic object class.
Asynchronous method invocation is specified by terminating the method invocation ex-
pression by the symbol “&.” An asynchronous method invocation expression returns a newly
created CBox object. The caller may bind the CBox object to a variable and use it later for re-
ceiving the result of an asynchronous method invocation. The result associated with the CBox
object is obtained by invoking areceive method defined on CBox objects. If the result is not
available whenreceive is invoked the invoker is suspended. CBox objects are used for synchro-
nizing the caller of an asynchronous method invocation with the called object and act as a private
communication channel for getting the reply. Without CBox objects, it would be difficult for the
sender of an asynchronous message to identify the replies.
The atomic object class is used to define subclasses whose instances have the property that
execution of their methods is mutually exclusive. This is needed for preventing problems that
may be caused by concurrent execution of an object’s methods.
A problem with the concurrency features in the first design of ConcurrentSmalltalk[90]
was that it provided limited support for condition synchronization. There was no means for se-
lective acceptance of messages and no direct way to suspend the execution of method unless on
resorted to Smalltalk-80 semaphores. In a later version of the language [91] this was overcome
by introducing the concept ofsecretary objects. These are special objects that may be attached
to ordinary objects and are used for synchronizing the execution of threads within the object and
for managing the acceptance of messages.
Objects, apart from atomic ones, are ordinary Smalltalk objects that are internally concur-
rent. Communication takes place by remote procedure calls as in Smalltalk-80 or by a non block-
ing variant that may be combined with CBox objects for receiving the replies.
The object model could be characterized as heterogenous since two kinds of objects, atomic
and ordinary Smalltalk objects, are supported. However, unlike other languages that we consider
to have an heterogenous model the protection of objects is not enforced by the system. It is the
programmer that is responsible to define objects that are subject to concurrent access as atomic
ones. This not very different from the use of synchronization constructs in orthogonal languages
to protect shared objects from concurrent execution. This is why we consider it as a language
with an orthogonal object model.
Chapter 3 53
SR
SR (Synchronizing Resources) [10] is a programming language for distributed applications. Al-
though it is not advertised as an OOPL it supports several object-oriented features. Programs are
structured in terms of resources. A resource encapsulates variables and processes. Resource
specifications declare operations that are used for interacting with a resource. A resource may
be implemented as an abstract data type, by specifying a procedure for each operation, or by one
or more processes. Figure 3.3 shows a resource that implements a queue of integers as an ab-
stract data type.
Resources implemented as processes may selectively service operation invocations by us-
ing in statements. This is similar to Ada’s select/accept [8] but more powerful since it allows
guards to depend on the arguments of the invocation.
Resources are typed and may be created dynamically. Inheritance is supported by anextend
construct which is used to refine a resource specification and provide different implementations
of the resource’s operations. It is possible to defineabstract resources consisting only of a spec-
ification.
Figure 3.4 shows the implementation of a resource that extends the queue given earlier and
implements it by a single process so that it can be used as a bounded buffer. This ensures mutual
exclusion as only this process may access the resource’s state.
Figure 3.3 A queue in SR as a passive data type
resource Queueop insert(item: int)op remove() returns item: int
body Queue(size: int)var store[0..size-1] : intvar front := 0, rear := 0, count :=0
proc insert(item)if count < size -> store[rear]:=item; rear:=(rear+1)%size;
count++;[] else -> #take action appropriate for overflowfi
end
proc remove() returns item
... implementation of remove...end
end Queue
54 Classification of Existing Languages
Capability variables to abstract resources may be used to refer to any concrete resource that
extends an abstract resource by providing it with abody. It should be noted that this mechanism
may not be used for inheriting methods as in languages like Smalltalk-80, but it is solely used at
the operation specification level to express a subtype relationship.
Resources are concurrent objects. Threads are created either by reception of external mes-
sages, in the case that the resource is implemented as an abstract data type, or by the execution
of theco construct which is similar to a “cobegin.” Protection of a resource’s state from concur-
rent execution is achieved by implementing a resource as a single process as shown above for
the bounded buffer.
The object model of resources may be characterized as orthogonal. No distinction is made
between resources that are implemented as abstract data types whose operations should not be
called concurrently, and resources implemented as processes that control the activation of their
operations which can may therefore be invoked concurrently.
Resource interaction takes the form of remote procedure calls. A variant that does not
block the caller is also provided. However, there is no support for getting the result of a non
blocking call and thus results are discarded. Explicit acceptance of requests by “in” statements,
described above, is the main means for achieving conditional acceptance of requests.
Figure 3.4 A queue in SR implemented as a process
resource BoundedBufferextend Queue
body BoundedBuffer(size: int)var store[0..size-1] : intvar front := 0, rear := 0, count :=0
process bb
in insert(item) and count < size ->
store[rear]:=item; rear:=(rear+1)%size; count++;
[] remove() returns item and count>0 ->
item := store[front]; front:= (front+1)%size; count--; niend
end BoundedBuffer
Chapter 3 55
3.5.2 The Heterogenous Approach
PAL
The programming language PAL, used in the AVANCE [13] system, supports two kinds of ob-
jects:packets anddatatype values. Packets are associated with persistence, resiliency, synchro-
nized access and independent existence. Datatype values are instances of abstract data types.
Datatype values may only be used within a packet so that they are protected from concurrent ac-
cess by the serialized execution of the operations of the enclosing packet. A new thread may be
created for the execution of any PAL expression. Execution of an expression by a new thread
creates an instance of a process datatype that may be used in way similar to ConcurrentSmall-
talk’s Cbox objects for obtaining the computed result. Process communication takes place by in-
voking the operations of shared packets.
The distinction between packets and datatypes in PAL was made mainly because of the im-
plementation overhead associated with the execution of packets. The implementation of data-
type values has less overhead since execution of their operations does not have to be synchro-
nized. By restricting the use of datatype values within packets, datatype values are protected
from concurrent access.
The disadvantage of this approach is that datatypes and packettypes form two separate type
hierarchies that could contain objects with similar functionality: code that was written to operate
on datatypes may not be used for packettypes and vice versa. The decision of implementing an
object as a packettype or a datatype is left to the programmer, and it may depend on the intended
use of an object in a particular application.
With respect to our classification scheme, PAL supports an heterogenous object model. In-
ternal concurrency is supported by creating processes. However, these processes may not com-
municating by accessing concurrently the packets’ internal state but may communicate by in-
voking the operations of other packets. Communication is based on remote procedure calls. It is
also possible to generate non-blocking calls by executing the invocation expression by a new
thread. No mechanism is provided for conditional acceptance of requests.
Eiffel //
This is a concurrent extension [21]to the programming language Eiffel [54] that also takes the
approach of separating the object world into two kinds of objects:processes anddata objects.
Process objects are single threaded and when created execute the code of theirlive routine. A
56 Classification of Existing Languages
process object accepts operation invocations explicitly by aServe statement within its live rou-
tine. TheServe statement is parameterized by a name of an operation.If there are pending re-
quests for this operation the oldest is accepted and it is executed. If there are no pending requests
for the specified operation theServe statement has no effect and the execution of the live routine
proceeds at the next statement.
The operations of process objects are always invoked asynchronously. An approach some-
what similar to ConcurrentSmalltalk’sCBoxes and ABCL/1’sfuture type messages is taken for
cases where operations return a result. When an operation of a process object is invoked an ob-
ject representing the result is returned immediately. The caller is suspended when it attempts to
use a result that is not yet available.
Data objects do not have a live routine and their operations are invoked as ordinary proce-
dure calls. They may only be used within a process object so that their operations are never in-
voked concurrently.
As both theServe primitive and operation invocations are non blocking, it is rather difficult
to synchronize process objects. The only ways are to use busy-waiting or to use the result re-
turned by operations. For instance, if a process object wants to accept a message before proceed-
ing with the execution of its live routine, the serve primitive specifying the operation has to be
included in a loop. This weak approach to synchronization may lead to complex solutions to syn-
chronization problems, where unneeded return values are used merely for synchronization, and
complicate the protocols for object interaction.
ACT++
ACT++ [41] is a object oriented language that extends C++ [76] with concurrency features de-
rived from the actor model [1]. It supports two kinds of objects: actors and passive objects. Ac-
tors are active objects that serialize concurrent invocation of their operations. Passive objects are
ordinary C++ objects. They are constrained to be used only within actors so that their operations
may not be invoked concurrently. Any C++ object may be an actor if its class is defined as a
subclass of a predefined actor class.
The main communication mechanism is remote procedure call. Concurrent execution is
supported by thereply andbecome primitives. Thereply primitive is used within an operation to
return a reply to the caller. Statements following the reply statement in an operation are executed
in parallel with the caller. Thebecome primitive is inspired from the replacement behavior in the
actor model. An actor object may use this primitive to specify a behavior name that is used to
Chapter 3 57
indicate what message it is willing to accept next. Once the replacement behavior has been spec-
ified, through thebecome primitive, processing of messages may start according to the new be-
havior and in parallel with the statements following thebecome primitive in the old behavior.
The old and new behaviors do not share the actor’s internal state so no interference can occur
because of the parallel execution of behaviors.
Selective acceptance of requests is supported by the definition of behaviors, defined with
an actor class, in terms of the operations that they may process. Figure 3.5 sketches the definition
of an actor class that implements a bounded buffer of integers. The behavior part defines three
behavior names for bounded buffers. Theempty_buffer behavior accepts and processes the oper-
ationput. The behavior full_buffer accepts onlyget operations and the behaviorpartial accepts both
get andput operation invocations.
class bounded_buffer: Actor{
in_array buff[MAX];in in, out;behavior:
empty_buffer = { put()}full_buffer = { get() }partial_buffer = { get(), put() }
public:buffer(){
initialisation of the buffer ...become empty_buffer;
}insert an itemvoid put(in item){
if the buffer is now full
become full_buffer;else
become partial_buffer;}in get(){
return the next item ...reply buff[out++];if the buffer is now empty
become empty_buffer;else
become partial_buffer;}
}
Figure 3.5 A bounded buffer actor class in ACT++.
58 Classification of Existing Languages
Operationget illustrates the use of the primitivesreply andbecome. The next item in the
buffer is immediately returned to the caller by thereply statement, then the caller and the buffer
proceed in parallel. The buffer examines its internal state and chooses its replacement behavior.
The replacement behavior is specified by using thebecome primitive with the associated behav-
ior name.
The idea of behavior abstraction is interesting because it extends the data abstraction mech-
anism of sequential languages by including some information concerning the temporal aspects
of an object’s behavior. As a mechanism for selective acceptance of requests, it may be charac-
terized as a mechanism based on representation independent activation conditions. The condi-
tion for the acceptance of the request is that the object be in the appropriate abstract state spec-
ified by its current behavior. This is another interesting aspect of behavior abstraction that allows
it to be nicely combined with class inheritance. We will further discuss this issue in the next
chapter.
3.5.3 The Homogeneous Approach
ABCL/1
Objects in ABCL/1[92] are active entities that encapsulate a single thread of control. A variety
of message-passing constructs, including both one-way asynchronous message passing primi-
tives and higher level constructs, are provided for object interaction.
An object may be in one of the modes:dormant, active orwaiting. Objects are created and
remain in the dormant mode until they receive and start processing a message. While processing
a message an object is in the active mode. From the active mode it may go back to the dormant
or enter the waiting mode. An object goes from the active mode to dormant mode, when it has
finished processing a message and no further messages have arrived. It goes from the active
mode to the waiting mode when it has to wait to receive a message satisfying a particular con-
straint before it can do anything else.
Object interactions may have the form of remote procedure calls callednow type message
passing, asynchronous one-way message passing calledpast type message passing, and a form
called future type message passing. Future type message passing is a non-blocking variant of re-
mote procedure call where a special future variable is specified for storing the result to be re-
turned by the receiver. The sender may continue executing in parallel with the receiver and ob-
tain the result when needed by using this special variable. If the result is not available yet, the
sender is suspended. It is also possible for the sender to test if the result is available. Future type
Chapter 3 59
message passing is similar to the CBox objects feature of ConcurrentSmalltalk[90]. The main
difference is that CBoxes are first class objects. So, for instance, a CBox object may be passed
to another object than the caller for receiving the result. This effect can not be achieved with fu-
ture type message passing since the future variable is only accessible to the caller.
Objects are defined in terms of their state and theirscript. The state of an object contains
the definitions of its permanent variables which can only be accessed from within the script. The
script specifies the messages that are accepted by the object and the actions to be executed upon
receipt of a message. The specification of an acceptable message consists of the specification of
the mode in which the message is acceptable, a message pattern, an optional reply destination,
and an optional constraint.
The reply destination may be saved and a reply may be sent later using a past type message.
This allows an object to decide when to process requests even if they were issued by now type
messages. Even if a now type message has been accepted by an object further messages may be
accepted and processed before replying to the first message.
Figure 3.5 A bounded buffer in ABCL/1
[ object buffer( state [ s = ( create-storage 3)] )( script
( => [:put aProduct](if (full? s) then
(select( => [:get]
!(fetch s))))
( store aProduct s )!"done" ; return "done" as an acknowledgment
)( => [:get]@R
(case (fetch s)(is :empty
(select(=> [:put aProduct] ; sent to the consumer
[R <= aProduct] ; confirmation to producer
!"done")))
( is aStoredProduct[ R <= aStoredProduct ]
))))) ]
60 Classification of Existing Languages
Figure 3.5 shows a bounded buffer object that illustrates some of these features. In the dor-
mant mode the buffer accepts messages that match the message patterns:put aProduct and :get.
Accepting a:put message binds the variableaProduct to what follows:put in the message. When
a put message is accepted if the buffer is full it goes into waiting mode by executing theselect
statement. This allows the buffer object to wait until aget message is received. When aget mes-
sage arrives an item is removed from the store of the buffer and is sent to the object that sent the
get message, then the item to be put in the buffer is inserted in the storage and an acknowledg-
ment is sent to the sender ofput.
If a get message is accepted when the object is in the dormant mode the reply destination
for this message is bound to the variableR. If the buffer is empty the object enters the waiting
mode and waits for aput message. When aput message arrives the item contained in theput mes-
sage is immediately sent to the reply destination of theget message, saved in variableR, and an
acknowledgment is returned to the object that sent theput message.
The reply destination of a message is determined implicitly for now type messages and fu-
ture type messages. In general for past type message there is no reply destination since no reply
is expected, but it possible to explicitly specify a reply destination for past type messages. This
is very useful when an object wants to forward a request sent to it, with a now type message, to
another object.
Another interesting feature supported isexpress mode messages. A message sent in express
mode has the effect of interrupting processing of a message that was sent inordinary mode. After
the express message has been processed the object may choose between resuming its previous
activity or aborting it. This feature is very useful when there is a need to interrupt an object while
it is executing.
This feature could be simulated in languages that allow objects to peek at messages sent to
them. Still, it would be painful to program it explicitly. Every now and then the code of ordinary
messages should examine the message queue and take the appropriate action.
The usefulness of this feature is illustrated in [92]by an example of a team of problem solv-
ers working on a problem in parallel. When the first of them finds a solution it interrupts the oth-
ers by sending them a message in express mode.
To avoid arbitrary interleaving of the actions associated to messages, an object explicitly
specifies what messages may be received in express mode. Also, atomic blocks may be used for
making sure that certain sensitive blocks of code are executed atomically, i.e., they may not be
interrupted by express mode messages. ABCL/1 does not support classes or types of objects, but
Chapter 3 61
it is possible to define generator objects that are used to create several objects from the same ob-
ject description. Figure 3.6 which shows an object that is used to create bounded buffer objects.
ABCL/R
ABCL/R [86] is a reflective extension to the language ABCL/1 discussed above. The system’s
reflective architecture is based on meta-objects. That is, each objectX has a meta-object,↑X
which models its structure and behavior. The meta-object is the object’scausally connected self
representation.The object may inquiry or modify itself by interacting with its meta-object, and
changes to the object’s state through execution in the object or by accessing the meta-object are
reflected to the meta-object and to the object respectively.
Each object has a default meta-object whose methods are triggered by events in the execu-
tion of the object such as the arrival of a message. These methods determine behavioral aspects
of the object such as the order that messages are accepted, what script is executed for what mes-
sage etc. As meta-objects are objects with their own meta-objects, the message acceptance be-
havior of an object may be modified dynamically by modifying through the meta-meta-object,
the meta-object’s methods that determine the object’s message acceptance behavior. Any mes-
sage acceptance and scheduling policy may be supported in this way by the appropriate redefi-
nition of the meta-object’s methods. A number of interesting examples of this use of meta-ob-
jects may be found in [86].
POOL-T and POOL2
In POOL-T [5] objects have a single thread of control which is activated when the object is cre-
ation and which executes the sequence of statements in the object’sbody. Communication and
synchronization takes place by remote procedure calls. An object may explicitly accept messag-
es by executing ananswer statement in its body that specifies a set of methods.A message asso-
ciated with one of these methods is accepted and the method is executed. The caller and receiver
Figure 3.6 A bounded buffer generator in ABCL/1
[ object create-buffers( script ( => :new
![ object...state and script as in Figure 3.5
])
)]
62 Classification of Existing Languages
synchronize during the execution of the method in a extended rendez-vous fashion. The caller is
blocked until the method executes areturn statement. Methods may also have a post-processing
section that is executed after the method has returned. This is useful if there are statements which
logically belong to the method but do not contribute in the computation of the result. There is
also aselect statement, like in Ada, that allows messages to be accepted conditionally. For ob-
jects that do not specify a body a default one is assumed which cyclically executes an answer
statement for accepting any message sent to the object.
The language POOL2 suppresses the select statement and provides a non-blocking variant
of remote procedure call. However, no support is provided for obtaining the result computed by
such a non-blocking method invocation.
Languages in the POOL family also support another notion of module than objects which
is called a Unit and is similar to an Adapackage. Units may define and exportroutines whose
execution may take place concurrently, so we could say that units are concurrent objects. How-
ever, Units are not first class objects in the sense that they may not be passed as arguments and
may not be created dynamically.
POOL-T and POOL2 do not support inheritance. The reason is that it was not clear how
inheritance interfered with subtyping and that there was no satisfactory way for inheriting the
object’s body or to add methods without having to modify it [3].
Inheritance is supported in POOL-I [7]which is the latest member to join the POOL family.
It is distinguished from subtyping which is based on signatures augmented with object proper-
ties.Considering inheritance as separate from subtyping eliminates certain problems [41] that
occur in languages where the two concepts are coupled, and provides the programmer with more
flexibility as the two features may used independently.
Object properties provide a form ofname type equivalenceallowing the programmer to en-
hance object types with semantic properties. An object type is associated with a set of identifiers
chosen by the programmer to describe behavioral properties of the type. A subtype, apart from
having a compatible signature, should also have a set of properties that contains that of its su-
pertype. However, as behavioral properties of objects cannot be checked by a compiler it is the
responsibility of the programer to use this feature consistently.
Hybrid
Hybrid [62] was discussed extensively in the previous chapter. Here we are just going to mention
how Hybrid’s concurrency features are related to the design space presented in this chapter.
Chapter 3 63
Hybrid supports a homogenous object model, as all objects are considered as active server-
like entities and protection of their internal state is provided by default. Objects are internally
quasi-concurrent. Internal threads are created by accepting messages, and scheduling of threads
within an object is controlled by delegated calls.
Conditional acceptance of requests is supported by the delay queue mechanism which is a
form of conditional acceptance based on activation conditions that depend on the object’s inter-
nal state.
Object interaction takes place in a remote procedure call fashion. An asynchronous opera-
tion invocation mode is also supported for operations defined as reflexes. This is used for sup-
porting concurrent execution in the system rather than for object interaction.
SINA
Object interaction in SINA [81]takes place by remote procedure calls. Messages sent to objects
are stored in an interface queue. Each object has a system defined object manager that manages
the interface queue and selects messages to be processed by the object. The object manager of
an object O is denoted↑O and it supports the operationshold() andaccept(). These operations
have the effect of setting the object’s interface in thehold andaccept state respectively. In the
hold state no messages are processed by the object. They are instead delayed in its interface
queue until the object interface goes to the accept state.
In the accept state the object’s interface alternates between the sub-statesblocked andfree.
In the free state a message is removed from the interface queue, a process is created for process-
ing the message and the interface moves to the blocked state. No further messages are processed
while the interface is in the blocked state. The interface goes back to the free state when the pro-
cess that caused the interface to go in the blocked state terminates. With this scheme messages
are processed serially and at most one process can run within an object at a time. Adetach() prim-
itive offers the possibility to process messages concurrently. When the process that caused the
interface to go to the blocked state executes this primitive the interface of the object goes to the
free state. This allows another process to be created for processing, concurrently with the “de-
tached” process, the next message in the object’s interface queue.
Objects in SINA may be methods or data objects. Data objects may be primitive objects
such as integers or instances of user defined abstract data types. Methods are associated with a
process description (i.e. the code of the method). Each time a message is sent to a method object,
a process is created, according to the message acceptance rules described above, to execute the
64 Classification of Existing Languages
process description with the formal parameters bound to the objects contained in the message.
Objects which are instances of abstract data types export a collection of method objects that may
be invoked by other objects. The invocation of such methods takes place by qualifying the meth-
od’s name by that of the invoked object. Invocation messages to exported methods are sent to
the object’s interface queue. Then, the object manager schedules the message for processing by
sending it to the queue of the invoked exported method object.
New object types are defined by grouping other data objects and methods together in a type
definition. A type definition specifies which objects (usually methods) are visible to other ob-
jects. This determines the type’s interface. Objects contained within a type definition may in-
voke thehold() andaccept() operations on object managers of other objects contained within the
type. This allows various forms of synchronization.
Although this model at first may appear extremely complex the resulting language is rather
simple. Type definitions resemble types or classes in other languages and method execution may
be understood as in other languages. Figure 3.7 illustrates this by the definition of a bounded
buffer type in SINA.
Figure 3.7 Bounded buffer in Sina
type buffer interface isbegin
method put( integer as item ) returns nil;method get() returns integer;
end;type buffer local isbegin
objects integer as itemcount, head, tail, buff[N];
initialbegin head := 0; tail := 0; itemcount := 0; ↑get.hold();end
methodsput:begin
itemcount := itemcount +1;if itemcount = N then ↑put.hold();buff[tail]:= item; tail := (tail+1) mod N;↑get.accept();return val;
end;
get: objects integer as val ;begin ... code for get ... end;
end;
Chapter 3 65
The initial statement is a process description for a process that is executed at the creation of
an instance of this type. After this process has terminated the interface of the object is in the free
state and messages may be processed. The execution of↑get.hold() by this process sets the inter-
face of the method get to the hold state by invoking the operationhold() on its object manager.
The interface ofget is now in the hold state which means that messages sent toget will be queued
until its interface goes to the accept state. The interface ofput is in the accept state so messages
sent toput may be processed.
When a message is sent toput, a process is created that executes the code of the methodput.
The code of this method appends an item to the buffer and if the buffer becomes full it sets the
interface ofput at the hold state so that no more messages will be processed byput, then it sets
the interface ofget to the accept state by invoking the accept operation on its object manager.
After the execution of the method terminates, messages toget may be processed.
With respect to our classification SINA adopts the homogenous object model since, by de-
fault, objects process messages sequentially and are thus protected from concurrent execution.
Objects are internally concurrent. The creation of internally concurrent threads is initiated by ex-
ternal messages and is controlled by the object with thedetach statement and the use ofaccept
andhold primitives on the object managers of exported methods. Conditional acceptance of re-
quests is supported by thehold primitive whose use for conditional acceptance of requests is sim-
ilar to Hybrid’s delay queues. This is a restricted form of conditional acceptance since the con-
dition, which is that the interface of the requested method be in the accept state, may not take
into account the invocation’s arguments.
3.6 Summary
Table 1 summarizes the nature of object threads for each language discussed in 3.5. Note that
for ACT++ and PAL, although multiple threads may execute within an object, no synchroniza-
tion problems can occur since they access different versions of the object’s state. In the case of
ACT++ the programmer specifies through the use of abecome primitive, inspired from the actor
model, when the new version of the object’s state is created. In PAL the management of object
state versions and concurrent execution is completely transparent to the programmer.
Table 2 shows how threads are created within objects. This may be either by the acceptance
of messages or by the execution of special statement. For languages where objects are single-
threaded neither choices are available so the corresponding rows are left blank. In these languag-
66 Summary
es the object’s thread is created at the object’s creation time and no further threads may be cre-
ated within objects.
Table 1 Intra object concurrency
Language Sequential Concurrent Quasi-Concurrent
ABCL/1 √ABCL/R √ACT++ √ConcurrentSmalltalk √Eiffel// √Emerald √Guide √Hybrid √PAL √POOL-T √POOL2 √Sina √Smalltalk-80 √SR √
Table 2 Creation of threads within objects
Language Execution message acceptanceof a statement
ABCL/1
ABCL/R
ACT++ √ConcurrentSmalltalk √ √Eiffel//
Emerald √Guide √ √Hybrid √PAL √ √POOL-T
POOL2
Sina √Smalltalk-80 √ √SR √ √
Chapter 3 67
Table 3 lists the mechanisms that are available for conditional acceptance of requests. It
should be noted that for languages that have an orthogonal object model unconditional accep-
tance is the default. This is however not listed in the table since this concerns object models and
here we are concerned with the mechanisms that are available for conditional acceptance of re-
quests.
Table 3 Request Acceptance
Language Unconditional Explicit activation reflectiveconditions computation
ABCL/1 √ABCL/R √ACT++ √ConcurrentSmalltalk √Eiffel// √Emerald √Guide √Hybrid √PAL √POOL-T √POOL2 √Sina √Smalltalk-80 √SR √
68 Summary
CHAPTER 4
Comparing the Design Alternativeswith Respect to Software Reuse
In the previous chapter we have shown a variety of ways in which concurrency features may be
combined with object-oriented ones. Although all these may be equally powerful for the con-
struction of concurrent programs, in this chapter we show that they are not equally successful in
drawing the benefits of object-oriented programming for software development. We show that
certain feature combinations do not adequately support object-oriented programming because of
the interference of features and identify a set of useful combinations of language design choices
that achieve a successful integration of object-oriented and concurrent programming concepts.
In order to evaluate the various design choices with respect to their support for OO pro-
gramming and software reuse, we formulate a number of requirements which express the inte-
gration of OO and concurrent programming concepts. The main idea behind these requirements
is that the support for concurrency in an OO language should not diminish the expected advan-
tages of OO features for software development. For instance, encapsulation should still protect
the internal state of objects from surrounding objects and it should still be possible to insulate
objects’ clients from implementation choices. This should make it possible to change the imple-
mentations without affecting an object’s clients provided that the interfaces are maintained and
that changes are, in some sense, behaviorally compatible.
The various design choices are evaluated by developing appropriate examples and consid-
ering application development scenarios illustrating that certain design choices fail to satisfy our
requirements.
Language Design Requirements for Reusability70
The discussion in this chapter assumes an intuitive understanding of behavior compatibility
for objects in the sense that two objects are behaviorally compatible if one may be used in the
place of the other. However, a notion of behavior compatibility for active objects that may ac-
cept requests concurrently, delay requests or only accept requests in a certain order is not easy
to define. This issue, which is not addressed in this chapter, is further discussed in the two fol-
lowing chapters.
We first start by presenting in 4.1our requirements for a satisfactory integration of concur-
rency and OO features. Then we present an example application and propose a number of reuse
scenarios. In 4.2.2 we explore the design space presented in the previous chapter and illustrate
using the example the design choices that fail to satisfy our requirements. Finally, in 4.6 we sum-
marize our observations and make some comments on the approach used in this chapter for eval-
uating the design of COOPLs.
4.1 Language Design Requirements for Reusability
The following requirements are motivated by the principle that reusable object classes should
make minimal assumptions about the behavior of applications that will use them.
1. Mutual Exclusion-Protecting the Objects’ State: The internal state of objects should be
automatically protected from concurrent invocations so that it will be possible to reuse
existing objects in concurrent applications without modification.
2. Request Scheduling Transparency:An object should be able to delay the servicing of
requests based on its current state and on the nature of the request. This should be accom-
plished in a way that is transparent to the client. Solutions that require the cooperation of
the client are not acceptable from the point of view of reusability since the client then
cannot be written in a generic fashion.
3. Internal Concurrency: The concurrency constructs should allow for the implementation
of objects that service several requests in parallel or that make use of parallelism in their
implementation for increased execution speed in the processing of a single request. This
could be done either by supporting concurrent threads within an object or by implement-
ing an object as a collection of concurrently executing objects. Whatever approach is
chosen it is important that internal concurrency be transparent to the object’s clients so
that sequential implementations of objects may be replaced by parallel ones.
4. Reply Scheduling Transparency:A client should not be forced to wait until the serving
object replies. In the mean time it may itself accept further requests or call other objects
Chapter 4 71
in parallel. It may even want that replies be directly sent to a proxy. Request scheduling
by the client should not require the cooperation of the server since this would limit the
ability to combine independently developed clients and servers.
5. Compositionality and Incremental Modification:Existing object classes should be re-
usable within new contexts without modification. Additionally, mechanisms for incre-
mental modification of classes such as inheritance must be designed with special consid-
eration given to concurrency to allow existing code to cooperate gracefully with modifi-
cations and extensions [41],[80].
4.2 Comparing the Language Design Choices
4.2.1 An Example Application
In order to compare the design choices and their combinations with respect to the reuse require-
ments, we shall refer to an instance of a “generic” concurrent program structure: theadministra-
tor inspired by [32]. The administrator is an object that uses a collection of “worker” objects to
service requests. An administrator application consists of four main kinds of components. The
clients issue requests to the administrator and get back results. Theadministrator accepts re-
quests from multiple concurrent clients and decomposes them into a number of subrequests. The
workload manager maintains the status of workers and pending requests.Workers handle the
subrequests and reply to the administrator. The administrator collects the intermediate replies
and computes the final results to be returned to clients.
The administrator is a very general framework for structuring concurrent applications. For
example, workers may be very specialized resources or they may be general-purpose compute
servers. The workload manager may seek to maximize parallelism by load balancing or it may
allocate jobs to workers based on their individual capabilities.
clients
administrator
workersworkload manager
Comparing the Language Design Choices72
The components described above identify functionally distinct parts of the application that
could have been developed independently and reused as indicated above to construct a new ap-
plication.These components do not have to be implemented as single objects and indeed as we
see later depending on the constructs provided by certain languages several objects will be nec-
essary for realizing the desired functionality. However, it should be possible to modify the im-
plementation of the above components without affecting the rest as if they were single objects.
The following points relate the language design requirements, presented in 4.1, to reuse is-
sues in the case of the example application:
• Mutual Exclusion: (i) workload manager reuse – the workload manager must be protected
from concurrent requests by the administrator.There may be cases where the administrator
does not invoke the workload manager concurrently. Although in such cases no protection is
needed workload managers that are not protected could not be reused in different concurrent
implementations of the administrator. In such a concurrent implementation the administrator
may use a collection of proxies that may invoke the workload manager concurrently; (ii)
worker reuse – workers should similarly be protected so that arbitrary objects may be used as
workers with various implementations of the administrator including concurrent ones;
• Request Scheduling Transparency: (iii) Genericity of clients, reusing the administrator with
different clients– the administrator must be able to interleave (or delay) multiple client re-
quests, but the client should not be required to take special action. In fact it should be possible
to implement any object as an administrator and it should not matter to the object’s clients if
the serving object happens to be implemented as an administrator;
• Internal Concurrency: (iv) client/worker reuse – the administrator should be open to concur-
rent implementation (possibly using proxies) without constraining the interface of either cli-
ents or workers;
• Reply Scheduling Transparency: (v) worker reuse – it must be possible for the administrator
to issue requests to workers concurrently and to receive their replies when it chooses without
special action by workers;
• Compositionality: (vi) administrator reuse – the administrator should be programmed in such
a way that its code may be easily reused for slightly different cases. This could be done by
modifying only some parts of the administrators implementation (parameterization, inherit-
ance, or other techniques may be appropriate).
There are other aspects of language design, apart from the concurrency features, that affect
the creation and use of reusable administrator applications, such as the support for generic or pa-
Chapter 4 73
rametrized classes and the support for dynamic binding. In our discussion however we concen-
trate on issues that are more specific to the concurrency features of languages and ignore those
issues which would also arise in sequential languages.
4.2.2 Exploring the Language Design Space
In order to explore and evaluate the COOPL design choices we have selected, we shall consider
in turn object models, client/server interaction and internal concurrency, administrator reusabil-
ity. Throughout, we shall refer to the reusability requirements of 4.1 and we will make use of the
administrator example to illustrate specific points.
4.3 Concurrent Object Models
By the requirement of mutual exclusion, we can immediately discount the orthogonal object
model as it provides no default protection for objects in the presence of concurrent requests. The
reusability of workers and workload managers is clearly enhanced if they will function correctly
independently of assumptions of sequential access.
The heterogeneous model is similarly defective since one must explicitly distinguish be-
tween active and passive objects. A generic administrator would be less reusable if it would have
to distinguish between active and passive workers. Similarly worker reusability is weakened if
we can have different kinds of workers.
Thehomogeneous object model is the most reasonable choice with respect to reusability.
No distinction is made between active and passive objects.
Note that it is not clear whether the performance gains one might expect of a heterogenous
model are realizable since they depend on the programmer’s (static) assignment of objects to ac-
tive or passive classes. With a homogeneous approach, the compiler could conceivably make
such decisions based on local consideration – whether a component is shared by other concur-
rently executing objects is application specific and should be independent of the object type.
4.4 Thread Structure and Object Interaction Mechanisms
Here we examine how the choice of constructs for object interaction coupled with the thread
structure of objects affect the reuse that may be achieved in the construction of administrator ap-
plications. We first start by considering sequential objects coupled with an RPC communication
mechanism since this is the closest to sequential languages. Then, we consider in turn the solu-
tions that are provided by maintaining sequential objects combined with non RPC communica-
Thread Structure and Object Interaction Mechanisms74
tion mechanisms and non-sequential object approaches. For each combination of features we
sketch the possible ways to implement administrator applications and examine to what extent
specific feature combinations satisfy or fail to satisfy the reuse requirements.
4.4.1 Sequential Objects
RPC
If we provide an object model where objects have a single thread of control and RPC as the only
communication mechanism, we quickly discover that this is not enough to satisfy the require-
ments of the administrator. In particular, a sequential RPC administrator will not be able to in-
terleave multiple clients’ requests as it will be forced to reply to a client before it can accept an-
other request. The only “solution” under this assumption requires the cooperation of the client,
for example: the administrator returns the name of a “request handler” proxy to the client, which
the client must call to obtain the result. In this way the administrator is immediately free to ac-
cept new requests after returning the name of the request handler. Such an approach is however
incompatible with the requirement on request scheduling transparency since scheduling of re-
quests by the administrator is not transparent to its clients.
Consider for instance that we would like to replace the sequential implementation of an ex-
isting object class by a parallel implementation where instances of the class act as administrators
for a collection of appropriate worker objects. In accord with our requirements we would like to
take advantage of encapsulation and data abstraction to replace the old implementation without
having to modify the programs that used it. This however is not possible since, as discussed
above, in order to be able to process client requests concurrently an object, implemented as an
administrator, has to have a different interface than an object having a sequential implementa-
tion.
The sequential RPC combination also provides limited support for reply scheduling by the
administrator. If the administrator invokes workers directly using RPC, its single thread will get
blocked until the invoked worker computes the result and returns the reply. This disallows the
administrator to invoke several workers in parallel or accept further client requests while a work-
er computes the result and receive the workers’ replies at a later time.
The limitation of the sequential RPC combination for reply scheduling can be overcome by
the use of “courier” proxies used by the administrator to invoke workers. Each time the admin-
istrator needs to invoke a worker it creates an appropriate courier proxy that will invoke the
worker instead. For getting a worker’s reply the administrator could invoke a method of the cor-
Chapter 4 75
responding courier or alternatively the courier could call an administrator’s method when the re-
ply becomes available.
The former alternative has the disadvantage that the administrator may get blocked if it in-
vokes the courier too early. This may never occur with the latter approach. However, the admin-
istrator has to manage local queues for replies that are sent to it and that it can not use immedi-
ately. Furthermore, each time a reply is returned it should check whether all the replies needed
so far for handling a client’s request are available so that it may proceed with the client’s request.
It would also be possible to have the workers cooperate with the administrator so that it
does not get blocked when invoking them. We have not considered such solutions as they require
that workers be coded specially to match the administrator’s needs which is incompatible with
our requirement, concerning request scheduling transparency, that any object could be used as a
worker.
We must either relax the sequentially constraint or the strict RPC protocol. The possibilities
are: (i) one-way message passing, (ii) explicit request/reply scheduling primitives (with or with-
out proxies), and (iii) internal concurrency.
One-Way Message Passing
An extreme solution in the direction of relaxing RPC is to support one-way synchronous or asyn-
chronous message passing. In this case the administrator is free to accept messages and reply to
them in the order it likes. One-way message passing has however some disadvantages.
A concurrent client may issue several requests to the administrator before it gets a reply. In
this case it is important for the client to know which reply corresponds to which request. Are
replies returned in the same order as requests? In the case of synchronous message passing an
additional difficulty is that the administrator may get blocked when it sends the reply until the
client is willing to accept it. Requiring the client to accept the reply imposes additional require-
ments on the client and makes reuse more difficult. Either a different mechanism has to be sup-
ported for sending replies or proxies have to be created.
One-way message passing is also inconvenient for coping with the interaction between the
administrator and worker objects. A difficulty with using one-way messages is getting the re-
plies from workers. As there are several workers that are invoked in parallel and potentially con-
current invocations of single worker it is difficult for the administrator to tell which reply is as-
sociated with which request.
Thread Structure and Object Interaction Mechanisms76
A solution to this problem is to create a proxy for each request. The proxy would carry out
the request and then send a message to the administrator containing the worker’s reply plus some
extra information used for identifying the request. As with sequential RPC the administrator will
also have to manage local queues for partially completed requests.
Build-in Support for Courier Proxies
The administrator implementations described above made use of proxy objects for carrying out
requests and for storing replies. In the case of a sequential RPC combination such proxies were
necessary for allowing the administrator to call workers without getting blocked. In the case of
one-way message passing, proxies were still necessary for allowing requests to be paired with
replies.
Although proxies are a general programming approach it is cumbersome to program and
use them explicitly. In fact unless the language supports classes with type parameters and a flex-
ible manipulation of method names, a new proxy class would have to be defined for each differ-
ent worker class in an administrator application.
Future variables in ABCL/1[92], theprocess type in PAL[13] and CBox objects in Con-
currentSmalltalk[90] provide functionality which is somewhat similar to the courier proxies that
were used by the administrator to call workers. These mechanisms could be used by the admin-
istrator to call workers without getting blocked and for collecting worker replies at a later time.
The advantage of these mechanisms over program-defined proxies is that they can be used
for calling workers of any class. Future variables, however, are not first class objects and so are
not as flexible. For instance, a future variable cannot be sent in a message allowing a different
object than the one that made the request to receive the reply.
A difficulty with build-in proxies is that the administrator may at some point in time have
to get blocked and wait for a further client request or the reply to a previous worker request. Un-
less a powerful synchronization mechanism that allows the administrator to wait on either of
these events the administrator may get blocked to obtain a reply/request that is not available and
thus ignores other requests/replies. This problem could be circumvented either by polling if a
non-blocking request acceptance mechanism is supported or by additional, explicitly pro-
grammed, proxies that would return the replies by invoking some administrator’s operation es-
pecially provided for that purpose. This way a synchronization mechanism for selectively ac-
cepting requests would allow the administrator to be woken up either for receiving the results of
a previous requests or for accepting new requests.
Chapter 4 77
Still, the administrator’s code may get quite involved. If there is no way to prevent being
woken up by messages containing client requests or worker replies that cannot be used right
away, local message queues will have to be managed by the administrator. So, it appears that
build-in proxies combined with single thread objects provide limited support for reply schedul-
ing by the administrator since one should again rely on the use of explicitly programmed proxies.
More Flexible Request/Reply Mechanisms
It is also possible to relax the RPC style of communication without going all the way to support
one-way message passing as the main communication primitive. This has the advantage that it
is possible to present an RPC interface to clients and, at the same time, obtain more flexibility
for processing requests by the administrator. This possibility is illustrated by ABCL/1[92] which
permits the pairing of RPC interface at the client side with one way asynchronous message pass-
ing at the administrator’s side. Moreover the reply message does not have to be sent by the ad-
ministrator object. This provides even more flexibility in the way that the administrator may
handle requests since the replies may be directly returned to the client by proxies. The following
segment of code shows how this is accomplished.
The RPC call at the client side looks like:
result := [ administrator <== :someRequest arg1 ... argn] ...
A message is sent to the administrator to execute the requestsomeRequest with argumentsarg1,
... ,argn. The client is blocked until the reply to the request is returned and the result is stored in
the client’s local variableresult.
At the administrator’s side the client’s request is accepted by matching the message pattern:
(=> :someRequest arg1 ... argn @ whereToReply.... actions executed in response to this request ... )
When the administrator accepts this request, the arguments are made available in the local
variablesarg1,...,argn and thereply destination of the request in the local variablewhereToReply.
The reply destination may be used as the target of a “past type,” i.e. asynchronous, message for
returning the reply to the client. As a reply destination may also be passed around in messages
it is possible for another object to send the reply message to the client. This action would look
like:
[ whereToReply <== result ]
wherewhereToReply is a local variable containing the reply destination, obtained by the message
acceptance statement shown above, andresult is the result to the client’s request.
Thread Structure and Object Interaction Mechanisms78
Another interesting way of using the possibility to combine one-way message passing with
RPC is for flexible reply scheduling by the administrator. In the previous section, on build-in
proxies, we mentioned that a difficulty was that the administrator should be able to wait for ac-
cepting both returned replies and further requests. A way to circumvent this problem was to use
explicitly programmed proxies that would return results by invoking some operation provided
by the administrator. In this way replies were returned by requests so that a request acceptance
mechanism was sufficient for allowing the administrator to wait for both requests and replies. A
different approach is possible by pairing one-way messages to the RPC interface supported by
workers. With this approach the administrator may use a past type message, with itself as reply
destination, for calling the workers which present an rpc interface. The replies from the workers
can then be received by the administrator as any past-type message request. This allows the ad-
ministrator to use the message acceptance mechanism for receiving both requests and replies.
This approach has however some of the drawbacks of one-way message passing: Some ex-
tra work is needed in order to find out which reply message is related to what request and also
that the administrator has to manage queues for replies that may not be used immediately.
4.4.2 Multi-threaded Objects
Another way for allowing the administrator to service several concurrent requests is by support-
ing multiple concurrent or quasi-concurrent threads. A separate concurrent thread may now be
used for handling each client request. However, depending on the mechanisms provided for
thread creation and scheduling it may still be necessary to resort to the solutions discussed pre-
viously in order to achieve a satisfactory level of concurrency in the processing of client re-
quests.
We consider in turn quasi-concurrent and concurrent approaches and examine the support
provided by the thread creation and scheduling mechanisms for programming administrators.
Quasi-Concurrent Approaches
A traditional example of “objects” with quasi-concurrent thread structure is provided by moni-
tors [38][16]. However, monitors present some well known difficulties such as “nested monitor
calls” and unduly constrain parallelism [52][72][15] when used as the main modular units of
concurrent programs. These limitations are due to some extent to the quasi-concurrent structure
of threads. However, an approach based on monitors would also constrain concurrency among
different objects because of its limited support for reply scheduling. Assuming that the admin-
istrator is a monitor, then when calling a worker the monitor would remain blocked until the in-
Chapter 4 79
voked operation would return. This situation calledremote delay[49] makes it impossible for the
administrator to accept further client requests or to call a second worker.
Consequently, certain object-oriented languages have adopted more flexible variations.
For example, Emerald [14] uses monitors as defined in [38]. However, not all operations of an
object have to be declared as monitor procedures and also several independent monitors may be
used in the implementation of an object.Lock blocks andwait queues in Trellis/Owl[60] also
allow for more flexible implementation schemes than if objects were identified to monitors.
With this approach however objects in these languages are not quasi-concurrent anymore.
The restricted support for concurrency among objects by monitors is not due to the quasi-
concurrent structure of objects, but rather to the limited flexibility for reply scheduling. This is
illustrated by the second quasi-concurrent approach we examine which by providing a more
flexible reply scheduling scheme does not restrict concurrency among objects.
Hybrid[62] is another language which adopts a quasi-concurrent thread structure for ob-
jects. However, in contrast to monitors the delegated call mechanism, discussed in detail in
chapter 2, provides a more flexible reply scheduling approach that does not restrain concurrency
among objects. The administrator may use the delegated call mechanism to invoke workers. In
such a case a new thread may be activated in the administrator for processing another client re-
quest in the meantime.
The delegated call mechanism is satisfactory for allowing the administrator to accept fur-
ther client requests while a worker is executing a previous request providing thus support for
concurrency among several client requests. However, it is of no help for allowing several work-
ers to execute in parallel for a single client request.
This may only be done by using proxies for invoking the workers or by a construct for spec-
ifying the creation of a new quasi-concurrent thread. Such a construct was supported in the orig-
inal design of Hybrid. The newly created quasi-concurrent threads would resume each other by
using delegated calls. This construct was not included in the prototype because it substantially
increased the complexity of the rules for message acceptance.
Concurrent Approaches
With concurrent threads it is straightforward to process several client requests concurrently by
creating a new thread for processing each client request. Provided that satisfactory mechanisms
are supported for constraining the creation and activation of concurrent threads this does not
cause the mutual exclusion problems of languages with an orthogonal object model. The con-
Compositionality and Finer Grain Reuse80
current execution that may take place is explicitly specified by the programmer and the scope of
the potential interference of the concurrent threads is restricted to the state of a single object.
Provided that there is some way to suspend the execution of a concurrent thread or avoid
its creation, languages that support concurrent threads provide adequate support for request
scheduling and for internal concurrency to the extent that several client requests may be pro-
cessed concurrently.
A different issue however that is not necessarily addressed by the support for concurrent
threads is the possibility to use concurrency for processing a single request. Unless the creation
of multiple threads can be initiated by the object, the support for reply scheduling of concurrent
threads is not sufficient for processing a request in parallel.
For example the language SINA [81] makes it possible to use several concurrent threads
within an object for processing requests; there is no direct means, however, for one of these
threads to create more threads for calling the worker objects in parallel. This is done indirectly
by creating a courier proxy, as described previously. It is therefore not necessarily redundant to
support both multiple threads and non-blocking communication primitives.
A satisfactory way for calling workers in parallel without using proxies or asynchronous
message passing is to support a construct by which more threads may be created in the object.
In this case a worker can be called by each of these threads in an RPC fashion. With quasi-con-
current threads, a call to a worker should trigger the execution of another thread. Such constructs
are provided in the original design of Hybrid[62] and in SR[10]. Hybrid’s construct was dis-
cussed above. In SR the code segment of the administrator that is used for issuing requests to
workers in parallel would look like this:
. co result1 := w1.doWork(...) -> loadManager.terminated(w1)// result2 := w2.doWork(...) -> loadManager.terminated(w2)ocglobalResult := computResult(result1,result2);...
4.5 Compositionality and Finer Grain Reuse
Our evaluation of language design choices focused on the support provided for developing re-
usable objects and for defining new object classes in a way that makes it easy to reuse objects of
existing classes. Class inheritance is another way for supporting reuse at a finer grain than whole
objects. However, it is hard to take advantage of inheritance in COOPLs because, as we dis-
Chapter 4 81
cussed in chapter 2 and as it was pointed out by other researchers [4][41][80], it interferes with
the concurrency constructs and encapsulation.
The design of COOPLs that make it possible to use inheritance is a research area in its own
right and it is a open research problem whether it is possible to design languages that take ad-
vantage of class inheritance and that satisfy our other requirements at the same time. Below we
will summarize some recent proposals for taking advantage of class inheritance in COOPLs and
comment on the support they provide for addressing our other requirements.
Interference between existing code to be reused (e.g., superclasses) and incremental mod-
ifications (e.g., subclass extensions) is due to (i) the difficulty of the additional code to synchro-
nize with the existing code and (ii) the difficulty of the existing synchronization code to be open
to modifications yet to be defined.
Taking as a criterion for the design of the synchronization mechanisms that the addition of
a new method by a subclass should not cause the redefinition of inherited methods, Kafura and
Lee [41] and Tomlinson and Singh [80] proposed independently two approaches which have in
common that the conditions for the synchronization of method execution do not refer directly to
the object’s instance variables and method names. They are instead expressed, indirectly,
throughabstract states andenabled sets, respectively, that may be redefined in a subclass in or-
der to account for the methods added by the subclass.
Although these approaches work well for the examples presented in [41] and [80], Matsuo-
ka et al. [55] showed, by an example, where all of the inherited methods had to be redefined in
a subclass, that this is not so in general. Also, the concurrency mechanisms proposed in both
these proposals do not adequately support reply scheduling. The proposal of Kafura and Lee is
also weak for request scheduling since activation conditions may not depend on message con-
tents.
Neusius [61] identifies the problem of combining inheritance and synchronization as: “The
dependency of the method specification and the synchronization protocol of an object is the
weak point that makes reuse and extensibility so difficult.” He proposes an approach where all
actions for specifying the synchronization of method execution are specified, separately from
the code of method, inmatching actions, pre-actions, post-actions associated with each method.
We agree with the above statement, however, in his approach, as in most work in the area
of “inheritance and concurrency,” the dependency of method specification with the synchroni-
zation protocol of an object seems to be understood in a rather narrow sense. That is, most of
this work seems to admit as a postulate that the dependencies, and the difficulties in reusing and
Conclusions and Summary82
extending the code of concurrent objects, will vanish if methods do not contain actions to, di-
rectly, synchronize their execution with that of other methods.
We believe that the dependency of method specification to the synchronization protocol of
an object is more deeply rooted. Consider for example a synchronization protocol that specifies
what methods or groups of methods may be executed concurrently without violating the integ-
rity of an object’s state. Clearly, if the code of some method is changed, so that it uses some more
instance variables, the synchronization protocol should also be revised to ensure mutual exclu-
sion with respect to the execution of other methods. Although the code of the other methods will
not have to be modified it will be necessary to modify the synchronization protocol, so the de-
pendencies still exist.
It would be interesting to investigate how to combine the approach proposed by Neusius
with other concurrency constructs so that it adequately addresses all of our requirements. How-
ever, as it is the case with other approaches for supporting inheritance in COOPLs, it is not easy
to tell on the basis of a couple of examples whether the approach allows inheritance to be used
effectively in concurrent object-oriented programs.
4.6 Conclusions and Summary
We can make the following observations concerning our exploration of reuse issues:
• Homogeneous object models promote reuse: concurrent applications can safely reuse objects
developed for sequential applications; efficiency need not be sacrificed.
• Sequential objects with strict RPC are inadequate: request scheduling and internal concurren-
cy can only be implemented by sacrificing the RPC interface; the solution is to either support
concurrent threads or to relax the strict RPC protocol.
• One-way message passing is expressive but undesirable: since higher-level request-reply pro-
tocols must be explicitly programmed, development and reuse of objects is potentially more
error-prone.
• Acceptance of concurrent requests is well-handled either by concurrent threads or by explicit
request/reply scheduling.
• Issuing concurrent requests is well-handled by one-way message passing, by proxies or by in-
ternal concurrency: the combination of both concurrent threads and non-blocking communi-
cation primitives may be appropriate for handling the separate issues of accepting and issuing
concurrent requests.
Chapter 4 83
• Built-in proxies used bysequential objects with non-blocking request issuing mechanisms
provide adequate support for reply scheduling but are weak at combining reply and request
scheduling.
• Both concurrent objects and multi-object approaches are useful for internal concurrency:
These approaches for internal concurrency are both useful for different purposes. Concurrent
threads make it easy to implement objects that may service several concurrent requests that
do not modify the objects state. Multi-object approaches are interesting when the implemen-
tation of a new object class, with internal concurrency, may be realized by using several con-
currently executing instances of existing object classes.
The evaluation of the design of the concurrency features of COOPL with respect to their
support for an object-oriented programming style was focused on the reuse of objects across ap-
plications and the possibility to reuse applications with modified implementations or extended
versions of object classes.
Languages that fail to satisfy our requirements will make it difficult or in some cases im-
possible to take advantage of the above aspects of reuse. However, more is needed for effective-
ly taking advantage of reuse potential of languages providing mechanisms that address our re-
quirements in a satisfactory way. Two essential issues are:
• Methods for the development of objects and application frameworks that provide high
reuse potential paired with criteria for evaluating and comparing the reuse potential of
alternative design choices.
• Providing the information necessary for safely reusing objects and application frame-
works. This information should provide in an abstract, rigorous and concise way the
specification of the behavior of objects in order to capture the behavioral constraints and
dependencies among objects of generic application frameworks. The semantic frame-
work which is the subject of the next section provides rigorous notion of object behavior
so that it is possible to specify the behavior of objects and to express and verify behav-
ioral constraints.
CHAPTER 5
A Unifying Framework forProcess Calculus Semantics ofConcurrent Object-BasedLanguages and Features
As shown in the previous chapter the various language design approaches are not equally suc-
cessful in integrating concurrency with the other OO features mainly because of the interference
between features. Such “design flaws” are generally uncovered only after the languages have
been fully designed and, possibly, implemented, by appropriate examples illustrating the inter-
ference of features[41][68][75][80]. We believe that a more rigorous approach for describing the
semantics of features, examining their interactions and comparing the various design choices
would be more effective for a satisfactory integration of the features.
An approach for the semantic definition of a concurrent programming language is by trans-
lation of the language constructs to a process calculus. This approach has been used in [58] for
the definition of a simple concurrent programming language by translation to CCS and also in
[65][83][85], using CCS or other process calculi for defining the semantics of concurrent object-
based languages. There are, however, different ways to translate the constructs of a language to
a process calculus. These may vary in the amount of operational detail or may use completely
different approaches for the translation of language features. This makes it hard to compare dif-
ferent language designs and draw useful conclusions about the interaction of a language’s fea-
tures.
In order to use the “semantics by translation” approach for examining the interaction of lan-
guage features and for comparing language designs we propose a framework for the semantic
86
definition of concurrent object-based languages by translation to CCS. This framework may be
used for the definition of the semantics of concurrent object-based languages that follow very
different approaches for object-based concurrency. For example, both languages that view ob-
jects as passive abstract data types and languages in which objects are considered as single
threaded message-passing processes can be accommodated. The proposed framework also sup-
ports class inheritance, for which, to our knowledge, no process-calculus semantic definition has
been given before.
The framework consists of the definition of a common base structure for the representation
of COOPL features, such as objects, messages, classes, methods and their synchronization, in
CCS. This structure is captured by the definition of a number of agents with agent parameters
that act as derived operators. These derived operators define a derived calculus on top of CCS
that more directly supports the description of semantics of COOPLs. The differences on lan-
guage design choices may be understood by variation of the definition of some of these opera-
tors. The underlying process calculus framework may be used for the analysis of the properties
of the operators that correspond to different language design choices.
Apart from supporting the rigorous description of the semantics of COOPL features this ap-
proach has the benefit that the meaning of an individual object is given as a CCS agent. This
provides us with a formal definition of object behavior and a notion of behavior equivalence in-
duced from the equivalence defined on CCS terms. It also makes it possible to use the underlying
formal, process calculus, framework for asserting and verifying properties of objects.
In section 1.1, we discuss our approach for capturing basic object-based features such as
object identifiers, messages, classes and instances in CCS. We assume knowledge of CCS and
the value-passing calculus used in [58]. We also use “functions” over agents which are ex-
pressed as definitions of agents with agent parameters as discussed in [58] chapter 9.
In section 1.2, we discuss how to map objects defined in object-oriented languages to CCS
agents in a way that essentially different approaches for combining objects and concurrency are
easily accommodated. We define a simple concurrent object based language named SCOOL and
give its semantics. In section 1.3, as an illustration of the suitability of the framework for lan-
guages following significantly different approaches, we present the semantics of a different ver-
sion of SCOOL.
In section 1.4 we extend the approach presented in the section 1.1 to include class inherit-
ance by defining object classes as agents that take agents as parameters. We extend the syntax
of SCOOL to include inheritance and give the semantics of the extensions.
Chapter 5 87
In section 1.5 we discuss alternative approaches for developing such a semantic framework
and for defining the semantics of concurrent object-oriented languages. We also compare our
choice of using CCS to what could be done by using a process calculus such as theπ-calcu-
lus[59] which supports label-passing, or a higher order process calculus such as CHOCS[79].
We also briefly discuss possible extensions and refinements of the framework.
5.1 Basic Framework: objects, classes and messages
A program consists of the parallel composition of agents representing the classes defined in the
program, agents representing predefined classes such as integers and Booleans, and a “start-up”
agent that represents the “main program.”
Classes are represented by agents that receive at the portrequestNewc, wherec is the class’s
name, requests for creating a new instance and supply at the portnewidc a value representing the
object identifier of the new instance. Some values may also be supplied at the requestNew port
to initialize the new instance.
Object identifiers belong to the set whereClassis the set of class names in
the program. Objects interact atrequestid,m andreplyk ports. A request port indexed byid, which
belongs to the set of object identifiers, andm, which belongs to the set of method names, is used
to send a message to the object identified byid requesting it to execute itsm method. A sequence
of the identifiers of the argument objects as well as a valuek used to identify the invocation are
transmitted as values along a request port.
The reply ports are used for communicating the object identifier of an object representing
the reply to a request. The reply ports are indexed by invocation identifiersk. These are values
supplied by the “caller” to allow different invocations to be distinguished. The portreplyk is used
by a caller to receive the reply to the request identified byk.
The use of reply identifiers may vary largely depending on the interaction primitives pro-
vided by the language. For modelling one-way message passing where the notion of reply is not
supported, reply ports and thus reply identifiers would not be used. For modelling single thread-
ed objects communicating by rpc the invoker’s object identifier would do. However, for lan-
guages that support multi-threaded objects or asynchronous invocations the invoker’s object
identifier would not be sufficient to identify the invocation. To cope with all these cases we as-
sume that reply identifiers are integers generated at each invocation by a global reply identifier
agent. This provides a means to uniquely identify each invocation in the system.
Oid ℵ Class×=
Basic Framework: objects, classes and messages88
The only object interaction mechanism discussed in this paper is remote procedure call.
However, the approach for identifying requests discussed above is adequate for modelling var-
ious ways of receiving replies to requests such asfuture variables in ABCL/1[92] and CBoxes
in ConcurrentSmalltalk[90].
5.1.1 The Structure of Class Agents
Agents representing classes will have a different structure depending on whether they corre-
spond to predefined object classes or program-defined classes expressed in an object-oriented
language.
5.1.1.1 Program-Defined Classes
The behavior of program-defined classes is described by the agent de-
fined below, which is parameterized by the class’s name and an agent ClassBeh that represents
the behavior of the class’s instances. The latter agent is obtained from the class definition ex-
pressed in a programming language and has two value parameters. These are bound at the cre-
ation of a new instance to a value representing the object identifier and sequence of values used
for initializing the instance. The way that agents that correspond to the behavior of instances are
obtained from a class definition is fully described in 1.2.2 for the example language SCOOL.
where
The definition of the agentClassis based on a family of agentsClk. Each of these agents
accepts at the port, requestNewname, a request for creating a new instance of the class, identified
by thename subscript, and receives inp a, possibly empty, sequence of values for initializing
the new instance. It outputs at the portnewIdname the value(k,name) which corresponds to the
object identifier of a new instance and then creates two new agents. The first of these agents rep-
resents the new instance and the second is the next agent,Clk+1, in the family of agents that will
handle the next instance creation request. The name subscript of the portsrequestNewname
and newIdname is the class name and is used to distinguish among requests directed to other
classes in a program.
Note the use of “=” in defining equations. For the definition of recursive agents we will use
either the recursion operator,fix, or recursive defining equations, choosing in each particular
case whichever is more convenient and produces a more readable result.
Class name ClassBeh,( )
Class name ClassBeh,( ) Cl0 name ClassBeh,( )=
Cln name ClassBeh,( ) requestNewname p( ) .newidname n name,( ) .=
ClassBeh n name,( ) p,( ) |Cln 1+ name ClassBeh,( )( )
Chapter 5 89
5.1.1.2 Predefined Classes
Generally object-oriented languages support a number of predefined object classes such as inte-
gers and Booleans. These are expressed in our framework by agents representing predefined
classes, which are composed with the user-defined ones in a program. In contrast to program-
defined classes that are expressed in the syntax of a programming language, agents for prede-
fined classes are directly expressed as CCS agents. However, predefined classes and their in-
stances conform to the protocol for agents representing classes and instances described above.
In section 3 we define agents corresponding to predefined classes for semaphores, Booleans and
integers that are used for the semantic definition of our example language.
5.1.2 Remarks
The approach for modelling object interactions at fixed ports indexed by object identifiers is suf-
ficient to model dynamic interconnections among objects which take place in object-oriented
languages by the communication of object identifiers among objects. At the CCS level all pos-
sible interconnections between agents representing objects are set up beforehand and object
identifiers act as switches in this huge interconnection network. We have, so far, found this ap-
proach satisfactory for modelling objects and it appears to be less cumbersome for modelling
some language features than what could be accomplished with theπ-calculus[59] which directly
supports dynamic interconnections. This is further discussed in section 1.5.
5.1.3 The Structure of Program Defined Objects
In this section we describe the structure of agents that represent objects whose behaviors are ex-
pressed in an object-based language. The mapping from class definitions to such agents is fully
described in section 1.2.2 for an example language. The motivation for taking this approach for
representing objects is to easily accommodate different object models and features. This will be-
come clearer as we elaborate on these issues in later sections.
Agents representing objects are structured as an assembly of agents. Some of these agents
are obtained from the object’s class definition while others are proper to the language’s object
model. Objects in languages that take substantially different approaches for their object models
are accommodated by the appropriate definition of the language dependent components. The
structure of objects is given in figure 5.1 and the purpose of the different kinds of components
is explained below.
Basic Framework: objects, classes and messages90
The Request Handler
This agent, defined below asRH, accepts requests, requestid,m(r,<v1,..,vn>) , for the execution
of one of the object’s methods identified bym. It creates anActivate agent, representing a pend-
ing request, which will interact with the appropriate method agent for the execution of the meth-
od. TheActivate agent has to wait for an signal from the method scheduler before
it interacts through acallm event with the method agent for executing the method.
This agent is very important for modelling inheritance in section 1.4.
Instance Variables
There is one such agent per instance variable. These agents are very similar to the agents used
for modelling variables in [58]. The main difference is that instead of storing integer and
Boolean values our variable agents store object identifiers. Also, our variable agents are defined
in such a way that they may be initialized at their creation.
The value (0,nil) standing for the identifier of the undefined object will be used to initialize
all non explicitly initialized variables. This object accepts any request sent to it and generates an
event indicating an error. This event could be used to model an exception handling mechanism,
however, exception handling will not be discussed any further.
requestid,m
replyk
Method Agents
Instance Variables
SELF
Request Handler
Method Scheduler
requestid’,m’
replyk’
Figure 5.1
activatem
RH id Meth,( ) fix X= requestid m, r v,( ). Activatem r v,( )|X( )m Meth∈∑( )=
Activatem r v,( ) activatem( ) .callm r v,( )=
VarV val( ) setV val'( ) .Var=V
val'( ) getVval.VarV val( )+
Chapter 5 91
In order to restrict access to a variable and thus model local variables and encapsulation we
define the access sortACCV of a variable V in way analogous to that in [58] as
. Restriction byACCV renders the variableV local to the scope of the restric-
tion.
Method Agents
There is one such agent for each object method. These agents accept activation requests contain-
ing values for the method’s arguments, they create an agent representing the method’s body in
an environment where “local” variable agents hold the arguments of the method activation. This
way several activations of a method may take place concurrently.
This agent is parameterized by the method namem and an agentMBody. It repeatedly ac-
cepts invocations at the portcallm where invokers supply a sequence of valuesv1,..,vn represent-
ing object identifiers, denoted here asa, for the method’s arguments and a valuer which is used
to identify where to send the reply.MBodyis the agent that is obtained from the definition of the
method in the modelled programming language in the way shown in section 1.2.
The Method Scheduler
The purpose of this agent is to control the concurrent execution of methods. It interacts with the
Activate agents created by the request handler, imposing synchronization constraints on the ac-
tivation of methods. By varying the nature of synchronization constraints imposed by this agent
on the concurrent activation of methods we can accommodate significantly different object mod-
els. This agent will also interact with the execution of certain method statements. For example,
consider a scheduler that does not allow method executions to take place concurrently. Before
generating an to enable the execution of a method it has to be informed that the execu-
tion of the previous method is terminated. This may be done by a event that is gen-
erated by the last statement of the executing method or by a “return” statement.
For modelling the synchronization of method execution that takes place in some languages
more information needs to be exchanged between the method scheduler and the execution of
method statements. For instance, to model languages with synchronization mechanisms derived
from path expressions [58] it is necessary to know which method has terminated. This would
require that the terminate events would carry information about the method name. As such in-
formation is not required by the scheduler of the languages discussed in this paper we have not
included such information to simplify the presentation.
ACCv getv setv{ , }=
Method m Mbody,( ) fix( X= callm r a,( ).Mbody r a,( ) |X)=
activatem
terminate
Defining SCOOL, a Simple Concurrent Object-Oriented Language92
The agentOrth defined below, is used for modelling languages with anorthogonal object
model where, as defined in chapter 3, objects are considered as passive abstract data types. Syn-
chronization of method execution in such languages is achieved within methods by the invoca-
tion of special objects as, for example, semaphores in Smalltalk-80 [34] or locks in Trellis/
Owl[60]. So, the schedulerOrth used to model objects in these languages does not impose any
synchronization constraints on the activation of an object‘s methods.
This scheduler agent is used in section 1.2 for defining the semantics of the language
SCOOL. In section 1.3 we discuss an alternative approach for method scheduling corresponding
to a different version of SCOOL.
Self
This agent operates as a “read-only variable” bound at object creation to the object’s identifier.
It is used by the object to find out about its own identity and class. This agent is used in the se-
mantics of languages where the pseudo variableself may be used for designating the object itself.
Its definition is:
Objects
Finally, an object is modelled by an agent defined as the concurrent composition of the above
agents and parameterized by its object identifier, which is used by the request handler for accept-
ing requests. Restriction is used to hide the events used for the interaction between the above
agents and eliminate the potential for interference with the events occurring in other objects.
5.2 DefiningSCOOL, a Simple Concurrent Object-Oriented Language
In this section we define a very simple object-oriented language for illustrating how the seman-
tics of various object-oriented features can be expressed in our framework. In later sections we
will extend the language by including more features and discuss how to accommodate them in
the basic framework.
5.2.1 Syntax and Informal Description ofSCOOL
The version of SCOOL discussed in this section does not support inheritance and takes an or-
thogonal approach for concurrency. The operations of objects are invoked in a remote procedure
Orth activatem.Orth terminate.Orth+m Meth∈∑=
Self id( ) getSelfid.Self id( )=
Chapter 5 93
call fashion by concurrent threads. The synchronization of operation execution has to be
achieved by the judicious programming of object methods.
A program consists of a sequence of class declarations, variable declarations and a state-
ment representing the “main” program.
The creation of a new concurrent thread is expressed by thefork expression. This expres-
sion is parameterized by a statement which will be executed by a new concurrent thread. The
value of thefork expression is the object identifier of an instance of the predefined classprocess.
Process objects allow threads to be synchronized. By invoking thewait operation of a process
object the invoking thread is suspended until the thread corresponding to the process object ter-
minates. Another means for thread synchronization is provided by invoking theP andV opera-
tions of semaphore objects which are instances of the predefined classsema.
We assume that the language is statically typed. This simplifies the semantics since we do
not have to consider the eventuality that a requested operation is not supported by the invoked
object.
Apart from the predefined classesprocess andsema mentioned above, SCOOL also sup-
ports predefined classes for integers and Booleans with the operations that are commonly attrib-
uted to these object types in programming languages. We also assume the existence of a single
predefined instance representing the undefined object. This object, denoted bynil, accepts re-
quests for any method and generates an event representing an error.
The syntax for SCOOL’s expression and statements is listed below, whereE andS, possibly
indexed, stand for expressions and statements respectively.
Expressions
X whereX is a variable
self the value of the executing object’s identifier
n wheren = 0,1,2...
b whereb = true, false
nil denotes the undefined object
new C(E1,..,En) create an object of classC
E.m(E1,..,En) rpc invocation where m is a method name
E1 = E2 comparison of the object identifiers
fork S Create a new thread for executing S
Defining SCOOL, a Simple Concurrent Object-Oriented Language94
Statements
X := E assignment
if E then S1 else S2 conditional
while E do S iteration
{ S} compound statement
S1; S2 sequential composition
skip no action
E. turn the expression E into a statement by discarding the result
return E return the value of E to the caller
Declarations
A declaration may be a variable declaration, a method declaration, a class declaration or a pro-
gram declaration
Decl ::= VarDecl + MethodDecl + ClassDecl + ProgramDecl
VarDecl ::= var X1:C,...Xn:C;
MethodDecl ::= method m (a1,..,an) { VarDecl S }
ClassDecl ::= Class C { VarDecl MethodDecl1...MethodDecln}
ProgramDecl ::= ClassDecl1 ....ClassDecln { VarDecl S }
5.2.2 Semantics
RequestIdGen is the agent used to generate identifiers for invocation requests. It is defined
as:
ProcClass, SemaClass, IntClass andBoolClass are the agents representing SCOOL’s pre-
defined object classes. These agents are defined in section 1.2.2.2.
Class Declarations
where
with
[[ ProgramDecl]] [[ ClassDecl1]] | ... | [[ ClassDecln]] | [[ VarDecl]] |=
RequestIdGen0( ) | [[ S]] | ProcClass| SemaClass| IntClass| BoolClass
RequestIdGen n( ) requestId n.RequestIdGen n 1+( )=
[[ class C { VarDecl MDecl1...MDecln } ]] Class C ClassBehaviorc,( )=
ClassBehaviorc id p,( ) Object id ms C( ) [[ VarDecl ]] | MethDecl, ,( )=
Chapter 5 95
and
Where L is a function defined in [58] that gives the sort of an agent. ms is a function that gives
the set of method names of a class.
The agents Class, the request handler agentRH, Self and the method scheduler Orth were
discussed in section 1.1.
ClassBehavior is parameterized by two value parameters the second of which is not used
in the SCOOL example. This second parameterp is needed, in geneneral, to supply values for
initializing new instances of a class. However, as in SCOOL we provide no way for initializing
instances at their creation this parameter is ignored. Also, the expression listE1,...,En in an ex-
pression “new C(E1,...,En)”, used for creating an instance ofC, will be typically empty except in
the case of some of the predefined classes discussed in 1.2.2.2.
Variable Declarations
Method Declarations
where
if
and with
TheMethod agent was defined in section 1.2. The“Before Terminate” expression is used
to intercept the event generated by the last statement in the method body and inform the
method scheduler with a event that the execution of the method is completed. TheTer-
minate agent is defined as andBefore is a binary operator over agents, de-
fined in 1.2.2.1, that activates its right operand after the left one has generated a event.
MethDecl [[ MDecl ]] | ... | [[ MDecln ]]=
Object id M X, ,( ) RH id M,( ) |Orth M( ) |Self id( ) |X( )=
\ L Orth M( )( ) \ L Self id)( )( ) \ L X( )
[[ var V1: C1, ... ,Vn: Ck]] Varv10 nil,( ) | ... |Varvn
0 nil,( )=
[[ method m a1 ... an, ,( ) { VarDecl S} ]] Method m MethodBody,( )=
MethodBody r<v1 ... vn>, , ,( ) =
( Vara1v1( )| ... |Varan
vn( ) |Varv1
nil( )| ... |Varvknil( )| ( [[ S]] r( ) Before Terminate) )
\ ACCv1...ACCvk
\ ACCa1...ACCan
VarDecl var V1: C1 ... Vk: Ck,,=
nil 0 nil,( )=
done
terminate
Terminate terminate=
done
Defining SCOOL, a Simple Concurrent Object-Oriented Language96
The event may also be generated directly by the return statement discussed in the
next section.
5.2.2.1 Expressions and Statements
The semantic description of SCOOL’s statements and expressions builds on the semantic de-
scription of the languageM0 given in [58]. However, apart from the fact that more statements
and expressions are introduced a slightly different approach has been taken for predefined ob-
jects and for the semantics of statements.
Objects such as integers and Booleans are handled in [58] by the semantics given to expres-
sions. Here, we represent integers and Booleans as predefined objects. This allows us to give the
semantics of expressions independently of whether they evaluate to objects of predefined or user
defined classes.
Another difference is that statements are mapped to parameterized agents. This is needed
because of the way that we define the semantics of the return statement and is further discussed
below.
Agents Representing Expressions
Expressions are mapped to agents that yield up the value of the expression at the port. The
combinatorInto defined below is used to allow an agent to refer to the value computed by an-
other agent representing an expression.
If Q is an agent expression where the variablex occurs free thenInto binds this variable to
the value computed byP.
The definition of this combinator is not exactly the same as that in [58]. There it is assumed
thatres is not in the sort ofQ,so the relabellingresis unnecessary. Here, as we do not make this
assumption, we have to relabelres to a labelb that we assume does not occur free in eitherP or
Q.
Statements and Sequential Composition
Agents that represent statements indicate their termination at the distinguished label. Se-
quential composition of two statements representing agents is expressed by the combinator
Beforedefined as:
terminate
res
P Into x( ) Q P b/ res[ ] | b x( ) .Q( ) \ b=
done
P Before Q P b/ done[ ] |b.Q( ) \ b=
Chapter 5 97
We also define the agent Donewhich will be useful in the definition of the semantics of state-
ments as
Semantics of Expressions
,
where
The semantics of the fork expression whose informal semantics was discussed in 1.2 merits
some explanation. The execution of this expression creates an instance of the predefined class
process, defined in 1.2.2.2, and yields its id as the result of the expression. This id may be used
for invoking the wait operation of the process object which allows the invoker to be suspended
until the execution of the associated statement terminates. Then it creates an agent for executing
the forked statement as well as an agent that monitors the termination of this statement and in-
forms the associated process object. The termination of the “forked” statement is signaled by
and the process that monitors its termination uses the event to inform the process ob-
ject with idx that the execution of its associated statement has terminated.
Done done.0=
[[ X ]] getX x( ) . res x=
[[ self ]] getSelf x( ) . res x=
[[ n ]] res n int,( )=
[[ true ]] res 1 bool,( )= [[ false ]] res 0 bool,( )=
[[ nil ]] res 0 nil,( )=
[[ new C E1 ... En, ,( ) ]] [[ E1 ]] Into x1( ) ... [[ En ]] Into xn( )=
newRequestC x1 ... xn, ,( ) .newIdC x( ) . res x
[[ E. m E1 ... En, ,( ) ]] [[ E ]] Into t( ) [[ E1 ]] Into x1( ) ... [[ En ]] Into xn( )=
requestId k( ) . requestt m, k x1 ... xn, ,( ),( ) . replyk x( ) . res x
[[ E1=E2 ]] [[ E1 ]] Into x1( ) [[ E2 ]] Into x2( ) Comp x1 x2,( )=
Comp i1 c1,( ) i2 c2,( ),( ) =
if c1=c2then ifi1= i2thenres 1 bool,( ) + if i1 i2thenres 0 bool,( ) +≠
if c1 c2thenres 0 bool,( )≠
[[ fork S ]] newRequestproc.newidproc x( ) . res x. [[ S ]] | done. termx( ) \ done=
done termx
Defining SCOOL, a Simple Concurrent Object-Oriented Language98
Semantics of Statements
Apart from “E.”, the return statement and the fact that statements are mapped to parameterized
agents, statements and their semantics are the same as those defined in[58] for the languageM0.
“E. ” provides a way to turn expressions into statements by discarding the result yielded by the
expression and by generating the event as required by statements representing agents. It is
useful when a method is invoked for its side effects rather than for its return value. Its semantics,
given below, is straightforward and merits no further discussion.
The return statement deserves some more explanation. Actually it is because of this state-
ment that we have to map statements to parameterized agents. In order to reply to the right caller
the agent representing the return statement has to be parameterized by a value to be used as the
subscript of the reply label. This value is made available in the agent representing method dec-
laration and is passed down to the return statement of a method activation by syntactically en-
closing statements. In fact agents representing the semantics of statements other than the return
statement have no use for this parameter which is either ignored or passed on to the agents cor-
responding to component statements if there are any. The return statement also differs from oth-
er statements in that it does not pass control to the next statement throughdone.Thus, the exe-
cution of a method stops when it encounters a return statement. Instead it generates a
event, directed to the method scheduler, to indicate that the execution of the method has termi-
nated. In case there is no return statement in the method the terminate event is generated by the
MethodBody agent defined in section 1.2.
where
done
terminate
[[ X:= E ]] k( ) [[ E ]] Into x( ) setXx.done( )=
[[ E. ]] k( ) [[ E ]] Into x( ) Done=
[[ { S} ]] k( ) [[ S ]] k( )=
[[ if E then S1 else S2 ]] k( ) =
[[ E ]] Into x( ) if x= 1 bool,( ) then [[ S1 ]] k( ) else [[ S2]] k( )( )
[[ while E do S ]] k( ) W k( )=
W k( ) fix( X= [[ E ]] Into x( ) if x= 1 bool,( ) then [[ S ]] Before XelseDone( )=
[[ S1; S2 ]] k( ) [[ S1]] k( ) Before[[ S2]] k( )=
[[ skip ]] k( ) Done=
[[ return E]] k( ) [[ E ]] Into x( ) replykx. terminate( )=
Chapter 5 99
5.2.2.2 Predefined Object Classes
The structure of the process and semaphore predefined classes is the same as the one for user
defined classes so that theClass agent defined in section 1.1 is used for their definition. The only
difference from program-defined classes is that the agents that represent the behavior of instanc-
es are directly encoded in CCS. A quite different approach is illustrated by the agents represent-
ing the predefined Boolean and integer classes.
Process Objects
The purpose of process objects is to delay the invokers of theirwait operation until the thread to
which they are associated terminates. Termination of the thread is signaled to process objects by
a termid event whereid is the object’s identifier, after which the object accepts wait requests,
thus allowing its callers to proceed.
Semaphores
The agentSemaClass, defined below, represents a predefined semaphore class used to create
semaphore instances which are modelled as instances of the SemBehavior agent with the param-
eters bound to the corresponding object identifier. For simplicity we have ignored issues con-
cerning the order in which suspended callers are woken up.
where
,
for and
Booleans
To represent integers and Booleans we take a slightly different approach from the one used
above for semaphores. Here the agents corresponding to the predefined classes directly provide
the behavior of their instances.
ProcBeh id( ) termid. fix X = requestid wait, k ( ),( ) . replyk.X( )=
ProcClass Class process ProcBeh,( )=
SemaClass Class sema SemBehavior,( )=
SemBehavior id p,( ) Sem1 id( )=
Semn id( ) requestid v, k( ) . replyk.Semn 1+ id( ) +=
requestid p, k( ) . replyk.Semn 1− id( )
n 1≥
Sem0 id( ) requestid v, k( ) . replyk.Sem1 id( )=
Defining SCOOL, a Simple Concurrent Object-Oriented Language100
The predefined class for Booleans is given below by the agentBoolClass.This agent is de-
fined as the parallel composition of two agents:InstBeh andClassBeh. TheInstBeh agent real-
izes the behavior of the instances of the class which are identified by(0,bool) and(1,bool) for
the objects corresponding to the truth values true and false respectively. For encoding the oper-
ations on Booleans we have made the assumption that Boolean values and the usual Boolean op-
erations are subsumed by the process calculus and we use the symbols 0 and 1 to denote the val-
ues true and false respectively. This assumption, which was not strictly necessary, as we could
have encoded these operations by operations on integers, was made for convenience and in-
creased readability. Also, note that the execution of operations on different Booleans takes place
concurrently as the “product” symbol is used in the definition ofInstBeh to denote parallel com-
position.
Apart from providing the operations of Boolean instances the agentBoolClassalso sup-
ports the behavior of agents representing classes, that is the protocol for the creation of the
class’s instances. This behavior, which is provided by the agentClassBeh, is supported so that
all agents representing classes exhibit uniform behavior. In fact, the object identifier value re-
turned by the Boolean class at the port is the same as the value received along there-
questNewbool port. This value is generated by the agent corresponding to the semantics of the
expressiontrue used, for example, as an argument in the expressionnew Boolean(true) that may
be used for explicitly creating a new instance of an object corresponding to the Boolean value
true. Also, note thatClassBeh handles requests for the creation of instances serially so that no
interference may occur among concurrent requests.
Integers
The predefined class of integers,IntClassis defined below in a way analogous to Booleans. In
order to shorten the presentation just some of the operations typically provided for integers in
programming languages are shown.
newidbool
BoolClass ClassBeh| InstBeh=
ClassBeh= fix( X = requestNewbool n( ) .newidbooln.X )
InstBeh = [ requestn bool,( ) not, r( ) . replyr not n bool,( ) . InstBeh|n 0 1,{ }∈∏
requestn bool,( ) and, r k bool,( ),( ) . replyr k and n bool,( ) . InstBeh]
IntClass IntClassBeh| IntInstBeh=
IntClassBeh requestNewint n( ) .newint n( ) . IntClassBeh=
Chapter 5 101
5.3 Accommodating Other Object Models
In this section we define a different version of SCOOL inspired by the language POOL-T[5] and
give its semantics. The facility with which this significantly different version of SCOOL is ac-
commodated provides some evidence concerning the suitability of the proposed framework for
a wide range of concurrent object-based languages.
In this version of SCOOL objects are single threaded active entities that explicitly accept
requests to execute their methods. Method invocation takes place by remote procedure calls. The
caller is suspended until the receiver answers the request and sends back a reply.
A statement, called the object’s body, is associated with each object and starts executing
when the object is created. Ananswer statement may be used in the object’s body to accept re-
quests for executing a method in a specified set. If there are no pending requests for any of the
specified methods the execution of the object’s body is suspended until such a request is made.
After the execution of a method the execution of the object’s body proceeds with the next state-
ment.
It is also possible that a class does not define an object body. In this case a default body is
assumed which repeatedly answers requests for any of the object’s methods.
We also introduce areply statement which is like return in that it sends a reply to the caller
but, unlike return, passes control to the next statement. This statement is used to achieve an ef-
fect similar to POOL-T’s post actions.
5.3.1 Modifying the Syntax
The syntax of this version of SCOOL differs from the one in section 1.2.1 as follows.
Declarations
Class declaration is modified as follows to include the object’s body.
ClassDecl ::= class C { VarDecl MethodDecl1...MethodDecln BodyDecl}
class C { VarDecl MethodDecl1...MethodDecln }
requestn int,( ) minus, r k int,( ),( ) . replyr n k− int,( ) . IntInstBeh |
if n k≠( ) then replyr 1 bool,( ) . IntInstBeh)
( if n=k( ) then replyr 1 bool,( ) . IntInstBeh+requestn int,( ) equal, r k int,( ),( ) .
IntInstBeh= requestn int plus, , r k int, ,( ) . replyr n k+ int,( ) . IntInstBeh |n ℵ∈∏
Class Inheritance102
BodyDecl ::= body S
Statements
We extend the definition of statements to include theanswer andreply statements whose syntax
is defined as:
answer (M1,..,Mn) where M1,..,Mn are method names.
reply E
Expressions
We exclude thefork expression since in this version of SCOOL objects are single threaded.
5.3.2 Semantics
Class Declaration
In order to take into account the object’s body we modify the definition of the agentClassBe-
haviorc given in section 1.2.2 as follows.
where
if S is the body declaration for the class C and
if no body declaration is given in the declaration of C.
Method Scheduling
The scheduling of method execution is now done directly by the body so the scheduler in the
definition ofObject is 0.
Semantics of Statements
5.4 Class Inheritance
In this section we discuss how to extend the basic framework of section 1.1 to support class in-
heritance.
ClassBehaviorc id p,( ) Object id meth c( ) [[ VarDecl]] | MethDecl|Body, ,( )=
Body [[ S ]] Before 0=
Body [[ while true answer m1 ... mn, ,( ) ]]=
[[ answer m1 ... mn, ,( ) ]] activatem. terminate.Donem m 1 ... mn,{ , }∈
∑=
[[ reply E]] k( ) [[ E]] Into x( ) replykx.Done( )=
Chapter 5 103
First, we include a new agent component, calledSuper, in the assembly of agents that we
used for constructing an object. The purpose of this agen, as we will see shortly, is to allow meth-
ods defined in a class to invoke methods defined in a superclass despite the fact that they have
been overridden in the class.
Next, we modify the definition of agents representing the behavior of program-defined ob-
ject classes to be parameterized by an agent parameter rather than by a value representing an ob-
ject identifier. The resulting structure of agents is illustrated in figure 5.2(a). It is obtained from
figure 5.1 by the addition of SUPER and the introduction of a place holder for an agent in place
of the agent components of figure 5.1.
Figure 5.2
Method Agents
SUPER
Instance Variables
Method Agents
SUPER
Instance Variables
SELF
Request Handler
Method Scheduler
Method Agents
SUPER
Instance Variables
Class definition
Instantiation
Subclass creation
SUPER
without inheritance(a)
(b)
(c)
Class Inheritance104
The hole in figure 5.2 can be filled in either by an agent equal to the composition of the
components that were removed from figure 5.1 as illustrated by figure 5.2.(b) or by another
agent with a hole as in figure 5.2(c). The first way to “fill the hole” is used to produce the be-
havior of instances. The second represents class inheritance where two classes are composed to
yield a new class.
5.4.1 Extending SCOOL to Support Inheritance
In order to include inheritance in SCOOL we modify the class declarations as follows:
ClassDecl ::= class C BasicDecl
class C superclass C′ BasicDecl
BasicDecl ::= { VarDecl MethodDecl1...MethodDecln}
A class declaration may optionally specify, by using the keywordsuperclass as indicated above,
that the newly defined class C inherits an already defined class C′.
The semantics of inheritance used for this version of SCOOL is inspired by Smalltalk-80.
A subclass may define methods with the same names as that of its superclass, in which case the
subclass method definition overrides the inherited one. The pseudo variablesuper may be used
by an object to invoke a method of the superclass despite the fact that it has been overridden by
the subclass.
Instance variables defined in a class are accessible in methods of its subclasses and it is not
allowed to redefine them in a subclass.
The pseudo variableself may be used by the object to invoke one of its methods. Invoca-
tions through self will always cause the execution of the most specialized version of the invoked
method.
Method overriding and the super and self features are further discussed in section 1.4.3.
5.4.2 Agent Definitions for Modelling Class Inheritance
The agentObjectBehaviorc, defined below, represents the behavior of C’s instances, and is pa-
rameterized by their object identifiers.
where ms(c) is the set of method names of the class, including the method names of all methods
applicable to the class’s instances, i.e. the new methods defined byc and all the inherited meth-
ods.
ObjectBehaviorc id( ) Object id ms c( ) ClassBehaviorc, ,( )=
Chapter 5 105
ObjectBehaviorc is defined in terms of the agentsClassBehaviorc andObject. The former
is an agent with an agent parameter that represents the class C. It has the structure of the agents
with a hole shown in figure 5.2(c) and (a) depending on whether or not inheritance is used in C’s
declaration.
The agentObject fills in the hole of its agent parameter as illustrated in figure 5.2(b), with
the object agent components defined in section 1.1, yielding an agent representing the behavior
of instances of the class. It also restricts the scope of events used for communication between
object components. The way that restriction is used allows us to capture method overriding as it
will be explained in section 1.4.3
whereSch is some method scheduler agent andCl corresponds to the ClassBehaviorc agent for
some class C.
ClassBehaviorc for a class C is defined as follows:
1. if C is defined without making use of inherit-
ance.
2.
where bm(c)
is the set of method names defined inBasic Declc, if an already defined class C' is spec-
ified as C’s superclass.
The restriction ofsuper events in the second case above is necessary to ensure that interaction
will take place with the “right”Super agent. In the case where inheritance was used in the defi-
nition of C' the definition ofClassBehavior for C' also includes aSuper agent.
BasicBehaviorc is obtained from theBasicDecl part of a class C as:
if BasicDeclc = { VarDecl MethodDecl1 ... MethodDecln }, is theBasicDecl part of class’s
C’s declaration, the variables V1,..,Vn are declared inVarDecl.
TheSuper agent operates as an event transducer generating a for eachsuperm event
it consumes, withm in the set of the object’s methods.
Object id m Cl, ,( ) Cl RH id m,( )( ) |Sch m( ) |Self id( )( )=
\ L Sch m( )( ) \ L Self id( )( )
ClassBehaviorc X( ) BasicBehaviorc X( )=
ClassBehaviorc X( ) =
ClassBehaviorc' BasicBehaviorc X( ) | Super bm c( )( )( ) \ superm m bm c( )∈⟨ | ⟩( )
BasicBehaviorc X( ) =
X | [[ VarDecl ]] | [[ MethDecl1]] | ... | [[ MethDecln]]( )
\ ACCV1... \ACCVk
\ callm m bm(c)∈⟨ | ⟩
callm
Class Inheritance106
Semantics of Class Declarations
Finally the semantic mapping for class declarations is given as:
Where the agentClassis that defined in section 1.1, and the use of inheritance in the definition
of the class C is taken into account as discussed above in the definition ofClassBehaviorc which
is in turn used to defineObjectBehaviorc.
5.4.3 Overriding Superclass Methods, Self and Super
Overriding of methods is accomplished by the interplay of the restriction of the access sort for
method agents in the definition ofBasicBehaviorc and the operation of the request handler agent.
When a class is instantiated the request handler agent is instantiated within the scope ofBa-
sicBehaviorc whereC is the most specialized class in a chainC1,..,Cn of classes. Because of the
restriction of the access sort of method agents in the definition ofBasicBehaviorc the callm
events generated by the request handler for executing methodm will only be visible to the meth-
od agent form of the most specialized class that definesm. This is illustrated in figure 1.3.
Super meth( ) fix X = superm k a,( ) .callm k a,( ) .Xm meth∈∑( )=
[[ class C BasicDecl]] Class C ObjectBehaviorc,( )=
[[ class C superclass C' BasicDecl]] Class C ObjectBehaviorc,( )=
Figure 5.3
superm1
callm1
callm1SUPER
M1
M1
M2
requestself,m1
\callm1
RH
\callm1\callm2
C1
C2
callm2
Chapter 5 107
In some languages, such as Smalltalk-80[34], the pseudo-variablesuper in an expression
like super m1: x, indicates that the search for a method matching the method selector m should
start at the object’s superclass method dictionary. We capture the semantics of super as follows:
• The semantics for an expression involving super is given as:
This way the event will be able to get out of the restriction of the access sorts for methods
of the class. In the enclosing scope this event will be intercepted by theSuper agent and
transduced to a event which is released outside of the class scope of restriction. Thus,
the “search” for a matching method starts at the superclass level.
• A method invocation through the pseudo-variable self appearing in any of the methods of in-
herited classes should cause the invocation of the most specialized version of that meth-
od.This is achieved by using the agent Self to retrieve the object’s id and then using this id for
the call. As self is bound in the most restricted scope it will necessarily cause the invocation
of the most specialized method.
Figure 5.3 illustrates the above for a class C1 which inherits a class C2, having methodsm1
andm2, and which redefines methodm1.
5.5 Considering Other Process Calculi
For developing the framework we have considered two alternative calculi. Although these are
derived from CCS they incorporate features that substantially enhance its expressive power in
ways that are important for modelling some object-oriented concepts. In this section we will dis-
cuss the issues related to the use of these calculi as alternatives for the development of the se-
mantic framework as well as for modeling other object-oriented programming language fea-
tures.
The first of these is theCalculus of Higher Order Communicating Systems, CHOCS, [79]
which extends CCS by allowing processes to be sent and received as values. The second is the
π-calculus [59] where ports or labels may be communicated as values so that systems with dy-
namic communication links between their components may be modelled.
The ability to express systems with dynamic communication topology is essential for mod-
elling object-based systems where objects are created dynamically and object identifiers may be
transmitted in messages. Although we have considered using theπ-calculus for the semantic
[[ super .m E1 ... En, ,( ) ]] [[ E1]] Into x1( ) ... [[ En ]] Into xn( )=
superm k x1 ... xn, ,( ),( ) . replyk x( ) . res x
callmv
Considering Other Process Calculi108
framework we finally preferred using CCS. The main reason which is further discussed below
was that the semantic description of some language features was not as direct as one would ex-
pect.
The higher order approach of CHOCS could also be used to model systems with dynamic
communication topology since, as suggested in [79], it is equivalent in expressive power to
ECCS[31], the basis of theπ-calculus. However, in order to go from ECCS to CHOCS a trans-
lation using a kind of continuation semantics is needed. We did not consider taking this approach
for modelling dynamic interconnection since it appears to be less direct for modelling COOPLs
than the approach we used in 1.1.
Apart from modelling systems with dynamic communication topology, the higher order ap-
proach would be useful for modelling features found in some object-based systems that we did
not want to consider in the present framework. These include systems where classes are first
class objects as well as systems based onprototypes anddelegation[47].
For instance, with CHOCS, an object class may be modelled as an agent that stores the de-
scription of the agents corresponding to the class’s methods. Objects of the class receive the de-
scription of the method agents and execute them within a scope that restricts access to the ob-
ject’s instance variables. In this scope references to instance variables in the method agents are
dynamically bound to the instance variables of the instance that executes them. Dynamic chang-
es to classes and to the class inheritance hierarchy can be modelled by changing the description
of method agents held by the agent representing the class or by changing in instances the value
used to identify the agent acting as its class.
5.5.1 Modelling COOPL Features in theπ-Calculus
The ability of theπ-calculus to express the dynamic creation of ports and their communication
among agents is very attractive for modelling object-oriented languages. These features have
been used by Walker to model the semantics of some simple languages[85] in theπ-calculus.
We will first present how theπ-calculus may be used to model COOPLs in a way, basically the
one presented in [85], that takes advantage of the dynamic creation and communication of ports.
Next, we discuss some shortcomings of theπ-calculus and of the approach followed in [85] for
expressing some object-oriented features. Although the main ideas for modelling COOPL fea-
tures in theπ-calculus that we present below come from [85] we take a simpler approach for the
invocation of object operations. This is possible by taking a different approach, discussed at
length below, for modelling primitive objects, than the one followed in [85] that simplifies the
semantics of expressions.
Chapter 5 109
5.5.2 Usingπ-Calculus Ports to Represent Object Identifiers
Object identifiers are modelled by theπ-calculus ports that are used for interacting with the
agents representing the corresponding objects. These ports may be stored in variables and used
to communicate with the corresponding objects.
Variables can be modelled in a way similar to the one described in 1.1.3. The only differ-
ence is that now the values stored are ports used to represent object identifiers. The semantics of
the invocation of an object’s operation is to retrieve the port by communication with the variable
agent and then use the received port to communicate with the object.
A class C may be modelled as an agent,Class, that accepts requests for the creation of a
new instance at a portc, wherec is a constant name. For each request it creates a new port:id
which is communicated throughc to the caller. The new port is used for representing the object
identifier of the new instance and is bound to the parameter of an agent, hereObject, that is cre-
ated to represent the new instance.
The following protocol which avoids interference between concurrent requests is used to
model operation invocation. For each request received along the port representing its object
identifier the corresponding agent receives a “private” port that is used for receiving the infor-
mation associated to a request such as a name identifying the requested operation, the opera-
tion’s arguments and sending back the reply.
The agentObject defined below illustrates this approach. First, aprivate port associated
with a particular request is received along the portid. Next, a name identifying the requested op-
eration is received from the private port. According to this name the agent behaves as one of the
agentsMethod1,...,Methodn. These agents are parameterized by the request port which they use
to receive the operation’s arguments and return the result.
The agentCall(id,m,a,result) given below illustrates the sequence of actions that are exe-
cuted at the caller for invoking the operation identified bym of the object associated toid with
a single argument: a and receiving a port identifying the result which is sent along the portresult.
Class c( ) c id( ) . Object id( ) | Class c( )( )=
Object id( ) id r( ) . HandleRequest r( ) |Object id( )( )=
HandleRequest r( ) r : m1 Method1 r( ) ,…,mn Methodn r( )⇒ ⇒[ ]=
Call id m a result, , ,( ) id r( ) . r m. r a. r v( ) . result v=
Considering Other Process Calculi110
5.5.3 Comparing Object Identifiers
An issue that is not addressed by the languages modelled in [85] is the possibility to compare the
identity of two objects. In most object-oriented languages an expression like x = y wherex and y
are program variables may be used to compare the equality of the object identifiers stored in
these variables.
The only support offered by theπ-calculus [59] for the comparison of labels is provided
by the “match” operator defined as follows. The agent behaves asP if the
namesx andy are identical otherwise it behaves as 0, the inactive agent. If object identifiers are
modelled asπ-calculus ports, the match operator is not sufficient for describing the semantics of
an expression likex=y, since no action is possible if the compared labels are not identical.
In order to be able to use ports to represent object identifiers theπ-calculus should be ex-
tended with an operator that would better supports the comparison of two names. For instance a
“non-match” or an “if-then-else” operator defined in a way analogous to the match operator.
It would also be possible to use a less direct way for representing object identifiers. For in-
stance, object identifiers could be modelled as pairs of ports consisting of the port used to com-
municate with the agent representing the object and the port of an agent representing an integer
value. The comparison of object identifiers would take place by comparing the associated inte-
ger values which could be encoded in the calculus in the way presented in [85]. Such an ap-
proach however does not take advantage of the features of the calculus that made it in the first
place attractive for modelling object-oriented systems.
5.5.4 Primitive Objects and the Semantics of Expressions
Practically every object-oriented language supports a number of primitive object classes such as
integers and Booleans that are used as the starting point for defining other application specific
classes. With the CCS based approach we followed in 1.2.2 we represented primitive objects and
their classes as agents that observe exactly the same protocol as the agents representing the se-
mantics of program defined classes. With this approach the semantics of expressions, except the
ones that specifically concern primitive objects such as expressions consisting of integer or
Boolean constants, was defined uniformly independently of whether or not they involve primi-
tive objects.
A different approach was followed in [85] for modelling primitive objects using theπ-cal-
culus. With this approach objects of primitive classes such as integer and Boolean values are en-
coded as agents which do not observe the same protocol as the agents representing instances of
x=y[ ] x= y[ ] P
Chapter 5 111
program defined classes. The semantics of expressions takes into account the type of the objects
involved and in the case of primitive objects it depends on the structure of the agents that repre-
sent the objects of a particular primitive type.
With respect to the approach that we followed in 1.2.2 the above approach has the disad-
vantage that the semantics of expressions is not defined uniformly independently of the type of
the involved objects. Several cases have to be considered, one for each of the primitive types that
are supported by a particular language. We have considered two alternative approaches for mod-
elling primitive objects in theπ-calculus that overcome the shortcomings of the above approach.
The first approach is to reserve a fixed set of constant names to represent the object identi-
fiers of primitive objects and make use of these names in the encoding of the agents representing
the objects of the type. For example, the fixed constant portstrue andfalse and the agentsTrue
andFalse defined below illustrate this approach for the type Boolean.
The agentTrueencodes the behavior of the object corresponding to the Boolean value true.
It accepts requests at the fixed porttrue over which it communicates the name of a new private
port that is used for getting more information about and for replying to each request. The agent
TrueMethods which is parameterized by the port that is used for an individual request encodes
the operationsnot, or andand for this object.Not has no argument and returns as a result the
constant portfalse that corresponds to the agent that represents the object corresponding to the
Boolean value false.Or inputs from the request port a port corresponding to its argument. It ig-
nores the argument’s value and always replies by sending the port true that corresponds to the
object identifier of the object representing the Boolean value “true.”And inputs the port associ-
ated to its argument which is eithertrue or false and replies by sending back this same port. The
behavior of the agentFalse is analogous to that ofTrue. Integers and other primitive objects may
be represented in a similar way.
Note that only a finite number of integer objects may be represented by following this ap-
proach. This, however, is not a severe shortcoming for the description of the semantics of
COOPLs since we could assume an arbitrary but bounded number of integer objects in the en-
vironment.
True true r( ) . r op( ) . TrueMethods r( ) | True( )=
TrueMethods r( ) r : [ not r false or, r x( ) . r true and, r x( ) . r x ]⇒ ⇒ ⇒=
False false r( ) . r op( ) . FalseMethods r( ) | False( )=
FalseMethods r( ) r : [ not r true or, r x( ) . r x and, r x( ) . r false]⇒ ⇒ ⇒=
Concluding Remarks112
The second approach for representing primitive objects such as Booleans and integers is to
maintain the representation of integer and Boolean values as given in [85] but provide an object
interface to these representations so that the semantics of expressions may be defined in a uni-
form way for all objects. This may be accomplished by encoding objects of primitive types, say
integers, as follows. The agent representing the integer object stores the port of an agent that en-
codes an integer value in the way presented in [85]. Integer operations are realized by operating
on this representation, creating and returning a new integer object associated with the resulting
representation.
With this approach it is not necessary to fix a finite number of ports to be used as the object
identifiers of agents that represent integers. Each time an integer is returned as the result of an
operation on integers a new port could be created for the integer object associated with the inte-
ger value corresponding to the result of the operation. However, if a new port is used each time
that an integer object is returned as the result of an operation on integers different integer objects
would be used for representing the same integer value. The result of this would be that the se-
mantics of = based on the ports used for representing object identifiers would not coincide with
the equality of the integer values. A way to ensure that exactly one integer object is used for each
integer value is to have an agent in the environment that, based on the integer value, creates and
returns the port of an integer object. This agent would remember the ports used by integer ob-
jects associated with each integer value so that at most one integer object would be created for
an integer value. The main disadvantage of this approach is that it is heavily operational.
5.6 Concluding Remarks
We have presented a framework for describing the semantics of concurrent object-oriented lan-
guages and features. This framework captures the essential concepts found in COOPLs such as
objects and object identifiers, concurrent execution, classes and class inheritance. It provides a
high level description of the semantics of language features that makes it possible to compare
the different language design approaches and investigate in a formal setting the interaction of
features such as inheritance and synchronization.
The framework captures the common structure of object-oriented features by a set of defi-
nitions of agents with agent parameters. These parameterized agents may be viewed as the op-
erators of a derived calculus that supports in a more direct way object-oriented features and
makes it easier to describe and understand the semantics of COOPLs. The different language de-
sign approaches may be represented either by varying the agent parameters or by modifying the
definition of certain parameterized agents.
Chapter 5 113
Although CCS does not directly support the representation of systems with dynamic inter-
connection structure it is possible to encode object-oriented languages by assuming a static in-
terconnection network where any object may interact with any other object and where object
identifiers act as switches for communicating with a particular object. This could be done in a
more elegant and direct way by using theπ-calculus which directly supports the dynamic cre-
ation and establishment of communication links. However, in order to take advantage of these
features it is necessary to extend the calculus by an operator that better supports the comparison
of ports. Also, some more work is needed for representing primitive object types.
An important consequence of using a process calculus such as CCS as the target for the se-
mantics is that the underlying calculus may be used to formally specify and verify properties of
languages and systems.
The meaning of individual classes is given by a term of the calculus and it is possible to
use the calculus to examine whether this term is, in some sense, equivalent to an agent directly
expressed in CCS and which corresponds to the abstract specification of an object’s behavior.
Moreover, equivalence classes of CCS agents may be used as a specification of object behavior
that abstracts to some extent from a particular implementation of this behavior. We further dis-
cuss this issue in chapter 6.
The properties of the derived operators that we have defined, as agents with agent parame-
ters, for representing language features can be investigated by using the underlying process cal-
culus. The analysis of these operators and their interaction can be used to infer useful informa-
tion about the language design and the combination of the features of a language.
CHAPTER 6
Conclusion
The development of concurrent object-oriented languages that integrate object-oriented and
concurrent programming features is essential for taking advantage of object-oriented techniques
and their software reuse potential for constructing concurrent software. However, issues of con-
currency are not orthogonal to object-oriented concepts. Consequently, the benefits of the ob-
ject-oriented features do not carry over to languages providing arbitrary combinations of object-
oriented and concurrency features because of the interference of the object-oriented and concur-
rency features.
Another difficulty for taking advantage of the reuse potential of object-oriented techniques
for constructing concurrent software by reusing objects across applications and by enhancing ex-
isting object classes in an upward compatible way that does not break existing programs, it is
required to have a precise understanding of the behavior of objects. However, understanding the
behavior of objects and whether or not object behaviors are compatible, can be rather subtle in
the case of concurrent objects. We have addressed these problems by:
• A language design framework for understanding the interaction of concurrency and ob-
ject-oriented features in COOPLs and for comparing the language design choices with
respect to the integration of the concurrency and object oriented features. Using this
framework we have identified a number of combinations of language design choices that
satisfactorily integrate concurrency and object-oriented programming.
• A framework for the description of the semantics of COOPLs. This framework provides
a formal setting for specifying the semantics of COOPL features, examining their inter-
action and, most importantly, it provides a rigorous notion of behavior for concurrent ob-
jects.
116 Summary
6.1 Summary
6.1.1 Language Design Framework
6.1.1.1 Understanding the Language Choices
To understand the interaction of the concurrency and object features and what are the essentially
different approaches for the design of COOPLs we have constructed a design space that captures
the possible choices concerning three aspects of the language design.
• Object models: How are objects considered with respect to concurrent execution.
• Object threads: How many threads do objects have and how they are scheduled and created.
• Object interaction: What constructs are provided for objects to accept requests, issue requests
and receive replies.
Object Models
• The Orthogonal Approach: Concurrent execution is independent of objects which are consid-
ered as passive abstract data types shared by concurrent threads.
• The Homogeneous Approach: Objects are considered as active server entities that accept re-
quests from other objects.
• The Heterogeneous Approach: Both passive and active objects are supported. The languages
ensure that only active objects are used in places where the object’s operations may be in-
voked concurrently.
Object Threads
With respect to the number and scheduling of concurrent threads within an object, a language
may support one of the three kind of objects:
• Sequential: Objects have a single thread of control.
• Quasi-Concurrent: There can be more than one thread of control but only one is active at a
time. Thread switching is explicit.
• Concurrent: There are several, conceptually, parallel threads within the object.
There are two, non exclusive, ways for the creation of threads which are:
• By message reception: In this cases the creation of the thread is triggered by the arrival of a
message. There two disjoint subcategories according to whether the object may constrain the
creation of threads or not, that we have namedunconstrained andcontrolled thread creation.
Chapter 6 117
• Explicit creation: In this case a new thread may be created by the execution of a special con-
struct by an already active thread.
Object Interaction
We have examined the features provided for object interaction by considering separately the as-
pects related to issuing requests by an object playing the role of a client and accepting requests
by an object acting as a server.
We have divided the approaches for issuing requests into the following depending on
whether or not the mechanism support the notion of reply and the mechanisms for receiving the
reply to a request:
• One-way messages: Replies are not supported, they have to be sent as independent messages.
• Request/Reply: Support is provided for replies. We can further subdivide this category into
Remote procedure call andproxy based approaches. With the latter, the reply can be received
explicitly at a time that is determined by the caller.
Depending on whether or not some mechanism is supported for specifying which requests
may be accepted in the current state of an object, we distinguish betweenunconditional andcon-
ditional acceptance of requests. The following approaches may be used for conditional accep-
tance of requests:
• Explicit Acceptance: A statement is executed by the object to accept requests for calling some
of its methods.
• Activation Conditions: Each method is associated with a predicate that depends on the ob-
ject’s state and, possibly, on the method arguments. A call for a method is accepted only when
its associated condition is true. Activation conditions may berepresentation specific or ab-
stract. The former are expressed directly on the instance variables that are used in the imple-
mentation of the class. The latter are expressed on some abstraction of the object’s state.
• Reflective Computation: The arrival of a message activates the objects metaobject. The meta
object examines the state of its associated object and the contents of the message and decides
whether to call the requested method.
6.1.1.2 Language Design Criteria
For comparing the language design choices in each aspect of the language design space, we de-
veloped a set of requirements that express the integration of concurrency with object-oriented
concepts. The main idea underlying these requirements is that objects should make minimal as-
118 Summary
sumptions about applications that use them and about the behavior of objects with which they
interact. The features supported by COOPLs should make it easy to program such objects.This
main idea is refined in the following points:
1. Mutual Exclusion: The internal state of objects should be automatically protected from
concurrent invocations.
2. Request Scheduling Transparency:An object should be able to delay the servicing of
requests based on its current state and on the nature of the request. This should be accom-
plished in a way that is transparent to the client.
3. Internal Concurrency: The concurrency constructs should allow for the implementation
of objects that service several requests in parallel or that make use of parallelism in their
implementation for increased execution speed in the processing of a single request.Int-
ernal concurrency should be transparent to the object’s clients.
4. Reply Scheduling Transparency:A client should not be forced to wait until the serving
object replies. Request scheduling by the client should not require the cooperation of the
server since this would limit the ability to combine independently developed clients and
servers.
5. Compositionality and Incremental Modification:Existing object classes should be re-
usable within new contexts without modification. Additionally, mechanisms for incre-
mental modification of classes such as class inheritance must be designed with special
consideration given to concurrency to allow existing code to cooperate gracefully with
modifications and extensions.
6.1.2 Evaluating Design Choices and their Combinations
In chapter 4 we have examined the design choices and based on examples that illustrated the de-
sign choices, or combinations of design choices, that failed to address our requirements. We fi-
nally came up with a set of design choice combinations and guidelines for the design of COOPLs
that achieve a satisfactory integration of concurrency and object-oriented programming.
Request and Reply Scheduling
Request and reply scheduling can be supported equally well by sequential objects and multi-
threaded objects provided that these are combined with the appropriate object interaction mech-
anisms.
Chapter 6 119
In the case of sequential objects it is necessary to support a communication mechanism that
does not block the object’s single thread for receiving replies. The best solution, found in the
languages that we examined, is to use an approach that integrates one-way messages with rpc.
There is also the alternative to use proxies, provided that it be possible for the object’s thread to
wait on either the arrival of the reply by the proxy or the arrival of further requests. However,
no such mechanism was supported by any of the proxy based approaches that we examined.
In the case of multi-threaded objects, thread creation should be controlled by the object.
Supporting unconstrained creation of concurrent threads is similar to the orthogonal approach
for the language’s object model which violates the mutual exclusion requirement.
To support the request/reply scheduling requirements for quasi-concurrent threads it is nec-
essary to have a mechanism that allows another thread to be scheduled when the active thread
blocks for receiving the reply to a request. This is not necessary in the case of concurrent threads
since there may be other active threads within the object.
If rpc is chosen as the main communication mechanism it is also necessary to either support
explicit creation of threads or use proxies or one-way message passing for allowing to a single
thread to issue concurrent requests. If proxies are used, in the case of concurrent threads it is not
necessary, as in the case of sequential objects, to provide a mechanism for combining the accep-
tance of a request and a reply from a proxy. Separate threads can be used for each of these tasks.
Internal Concurrency
Internal concurrency can be addressed satisfactorily either by supporting concurrent threads or
by implementing an object as a collection of concurrent objects provided that the object interac-
tion constructs satisfactorily address request/reply scheduling. However, concerning the latter,
special care has to be taken so that the collection may present the same interface and be substi-
tutable with a single object implementation.
Both these approaches for internal concurrency are useful for different purposes. Concur-
rent threads make it easy to implement objects that may service several concurrent requests that
do not modify the objects state. Multi-object approaches are interesting when the implementa-
tion of a new object class, with internal concurrency, may be realized by using several concur-
rently executing instances of existing object classes.
6.1.3 Formally Specifying the Semantics of COOPLs and of Active Objects
For a rigorous description of the semantics of COOPL and of the behavior of objects specified
in these languages, we have developed, in chapter 5, a framework for describing the semantics
120 Open Problems and Future Research Directions
of concurrent object-oriented languages and features in CCS. The framework captures the essen-
tial concepts found in COOPLs such as objects and object identifiers, concurrent execution,
classes and class inheritance. It provides a high level description of the semantics of language
features that makes it possible to compare the different language design approaches and inves-
tigate in a formal setting the interaction of features such as inheritance and synchronization.
The common aspects of COOPL are captured by defining agents with agent parameters that
can be viewed as the operators of a derived calculus that allows a more direct description of the
semantics of COOPLs. The different language design approaches can be represented either by
varying the agent parameters or by modifying the definition of certain parameterized agents.
An important benefit of our approach for describing the semantics of COOPLs is that it pro-
vides a rigorous definition of the behavior of objects as a CCS agent. This allows the underlying
formal CCS framework to be used for reasoning and verifying behavioral properties of objects,
and provides us with rigorous notions of behavioral equivalence and substitutability of objects
induced by the corresponding notions on CCS agents.
6.2 Open Problems and Future Research Directions
6.2.1 Taking Advantage of Class Inheritance in COOPLs
Our language design requirements stated that the design of the concurrency mechanisms of
COOPLs should be easy to combine with mechanisms such as class inheritance to allow reuse
at a finer grain than whole objects. However, as it was shown in chapter 2 with the synchroniza-
tion mechanisms of Hybrid and as we discussed in chapter 4, class inheritance interferes with
encapsulation and synchronization. The design of synchronization mechanisms that can be suc-
cessfully combined with class inheritance is a research area in its own right. Moreover, the de-
sign of the synchronization mechanisms, apart from making it possible to take advantage of class
inheritance, should, at the same time, address the other requirements that we formulated for the
concurrency features of COOPLs.
The main trend in recent proposals for taking advantage of inheritance and finer grain reuse
have focused on separating the synchronization constructs from the method code. In that way
the code of inherited methods does not have to be modified in case that the synchronization con-
straints of a class that inherits a method, differ, with respect to this method, from the constraints
of the class where the method was originally defined.
With some approaches the synchronization constraints on the acceptance of requests may
have to be completely redefined in the subclass. In other approaches the synchronization con-
Chapter 6 121
straints may be inherited and combined with the constraints of other methods in the subclass.
Yet other approaches attempt to specify and reuse independently the “sequential part” of an ob-
ject and the synchronization specification.
The main problems with most of these approaches, as discussed in chapter 4, are:
• The synchronization mechanisms are weak for cases where a method has to be blocked
in mid-stream, allow another method to execute, and resume its execution at some later
time. However, supporting such behavior is essential for flexible reply scheduling.
• Although, the specification of synchronization constraints for a class is kept separate
from the method code they are not independent. The implementation of the methods is
known and the constraints are specified in a way that prevents the concurrent execution
of methods using the same instance variables. Changing the implementation of a parent
class may cause that the synchronization constraints in subclasses have to be modified.
As discussed in [75] having to modify subclasses after changing the definition of a parent
class is contrary to encapsulation.
6.2.2 Object Behavior, Behavioral Equivalence and Substitutability
An advantage of our approach to the semantics of COOPL is that it gives a clear meaning, rep-
resented by a CCS agent, to individual object classes. Thus, one can use the underlying theoret-
ical framework to reason about the semantics of classes and, motivated by substitutability, in-
vestigate notions of behavioral equivalence of object classes that are induced from equivalence
relations on CCS agents and alternatively try to capture formally at the CCS level intuitive ideas
about behavioral equivalence of object classes.
An interesting equivalence relation on object classes is the one induced by the CCS equal-
ity,= [58]. By the fact that the agents corresponding to the semantics of two object classes are
equal we may infer that the object classes and their instances may be safely interchanged in a
system. The behavior of the resulting systems, understood as agents, will be equal. This equiv-
alence relation has the benefit that it captures substitutability and to a certain extent abstracts
from the implementation of classes since actions related to the implementation, modelled as, si-
lent,τ- transitions, are ignored by this equivalence.
A closer examination reveals, however, that this object equivalence does not capture our
intuitions about what constitutes equivalent object behavior. For instance, the desired behavior
may be realized in a way that an object may have to communicate with other objects to which it
got acquainted at its creation or new objects it created to use them in its implementation. Clearly,
122 Open Problems and Future Research Directions
different implementations of the object’s behavior may exhibit different object creation and in-
teraction patterns. These actions however are not represented byτ-transitions since they are used
for the interaction of the object with its environment.
As another example, consider two objects that although may service the same requests, one
accepts and processes several “read-only” requests in parallel while the other accepts the same
kind of requests serially. Even if the difference in implementation of these objects is abstracted
by silent actions - if, for example, their methods just read their instance variables - these objects
are not equivalent because of the different possible patterns of request acceptance.
By using the semantic framework presented in chapter 5 we may investigate the properties
of alternative equivalence relations on CCS agents, for example those discussed in section 6.2.3
below, that capture our intuitions about the equivalence of objects and which induce a congru-
ence in the restricted classes of CCS contexts that correspond a particular language. Such equiv-
alence relations may also be used as the basis for comparing language designs. We can investi-
gate whether the features of the language design preserve the desirable equivalences, thus pro-
viding substitutability of equivalent objects, in order to identify problematic design choices.
An important consequence of using a process calculus such as CCS as the target for the se-
mantics is that the underlying calculus may be used to formally specify and verify properties of
languages and systems.
The meaning of individual classes is given by a term of the calculus and it is possible to
use the calculus to examine whether this term is, in some sense, equivalent to an agent directly
expressed in CCS and which corresponds to the abstract specification of an object’s behavior.
Moreover, equivalence classes of CCS agents may be used as a specification of object behavior
that abstracts to some extent from a particular implementation of this behavior.
6.2.3 Types as Behavioral Constraints for Active Objects
A closely related but different issue from behavioral equivalence is a notion of object type that
captures information about the behavior of active objects. Types in context of object-oriented
programming languages[20][80] may be understood as a predicate that is satisfied by the objects
that belong to the type. This view of types may be adapted to concurrent objects by suitable ways
to express as predicates behavioral constraints on the agents that represent the behavior of ob-
jects. Below we consider some ways for expressing predicates that capture behavioral con-
straints for concurrent objects.
Chapter 6 123
The most direct approach for expressing a predicate on the behavior of objects is to require
that the agent, corresponding to the meaning of the object expressed in some COOPL, be equiv-
alent to some agent, directly expressed in CCS, that is used to specify the behavior of objects of
a type. A type is the set of objects that satisfy this predicate, that is, the objects whose semantics
correspond to agents that are equivalent to the agent representing the type.
This approach however is a too narrow interpretation of types since it completely specifies
the behavior of objects and it fails to capture polymorphism and subtyping relations between
types. If an object satisfies the predicate of two types these types have to be equivalent. Also,
clearly, an object may not satisfy a type specification that does not include all of its operations.
Alternative approaches based on relations among agents are to consider asymmetric relations
and context dependent equivalences [45] between agents.
The approach of using asymmetric relations, suggested in [67], may be used to express sub-
typing relations between the agents that are used for the type specifications. A subtype should
be able to simulate every action of the supertype but it may also provide additional behavior that
is not provided by the supertype.
A context dependent equivalence relation may be used to express the substitutability of
agents within a certain context. A concrete case of a parameterized equivalence was presented
in [45] where bisimulation equivalence is parameterized by information aboutenvironments. An
environment consumes actions that are produced by an inner process. However the ability of the
environment to consume actions may be limited. Two processes are considered equivalent in an
environment if, in a sense, they are equivalence with respect to the actions consumed by the en-
vironment. Environments may thus be used to consider only the actions related to the set of op-
erations of a type.
Another interesting approach is to use some modal logic [58][36][46] for the partial speci-
fication of the behavior of objects represented as an agent. A type may then be understood as the
set objects whose behavior satisfies the partial specification. This approach also supports a no-
tion of subtyping as implication between modal logic formulas.
The above approaches for defining a notion of types can be used as yardsticks in the develop-
ment of type expression sub-languages for COOPLs that capture more information about the dy-
namic aspects of object behavior than those of actual COOPLs that approximate the notions sub-
stitutability induced by these notions of types.
References
[1] G.A. Agha,ACTORS: A Model of Concurrent Computation in Distributed Systems, The MIT Press, Cam-
bridge, Massachusetts, 1986.
[2] A.V. Aho, R. Sethi and J.D. Ullman,Compilers Principles, Techniques and Tools, Addison Wesley, 1986.
[3] S.Andler, ‘‘Predicate Path Expressions,’’ inProc. of 6th ACM POPL, SIGPLAN, ACM, 1979.
[4] P. America, ‘‘Inheritance and Subtyping in a Parallel Object-Oriented Language,’’ inProc. ECOOP’87,BI-
GRE, no. 54, pp. 281-289, June 1987.
[5] P. America, “POOL-T: A Parallel Object-Oriented Language,” inObject-Oriented Concurrent Program-
ming, ed. A. Yonezawa, M. Tokoro, pp. 199-220, The MIT Press, Cambridge, Massachusetts, 1987.
[6] P. America, ‘‘A Behavioural Approach to Subtyping in Object-Oriented Programming Languages,’’ inPro-
ceedings of the Workshop on Inheritance Hierarchies in Knowledge representation and programming Lan-
guages, pp. 141-156, Viareggio, Italy, Feb. 1989.
[7] P. America and F. van der Linden, ‘‘A Parallel Object-Oriented Language with Inheritance and Subtyping,’’
Proc. OOPSLA’90, SIGPLAN Notices, vol. 25, no. 10, pp. 161-168, ACM Press, October 1990.
[8] American National Standards Institute, Inc.,The Programming Language Ada Reference Manual, Lecture
Notes in Computer Science 155, Springer-Verlag, 1983.
[9] G.R. Andrews and F.B. Schneider, ‘‘Concepts and Notations for Concurrent Programming,’’ ACM Comput-
ing Surveys, vol. 15, no. 1, pp. 3-43, March 1983.
[10] G.R. Andrews, R.A. Olsson and M. Coffin, “An Overview of the SR Language and Implementation,” TO-
PLAS, vol. 10, no. 1, pp. 51-86, ACM, January 1988.
[11] H.E. Bal, J.G. Steiner and A.S. Tanenbaum, ‘‘Programming Languages for Distributed Computing Sys-
tems,’’ ACM Computing Surveys, vol. 21, no. 3, pp. 261-322, September 1989.
[12] T. Biggerstaff and C. Richter, ‘‘Reusability Framework, Assessment and Directions,’’ IEEE software, vol. 4,
no. 2, pp. 41-49, March ’87.
[13] A. Bjornerstedt and S. Britts, ‘‘AVANCE: An Object Management System,’’Proc. OOPSLA’88, SIGPLAN
Notices, vol. 23, no. 11, pp. 206-221, ACM, san diego, November 1988.
[14] A. Black, N. Hutchinson, E. Jul and H. Levy, “Object Structure in the Emerald System,” Proc. OOPSLA’86,
ACM SIGPLAN Notices, vol. 21, no. 11, pp. 78-86, Nov 1986.
[15] T. Bloom., ‘‘Evaluating Synchronization Mechanisms,’’ inProceedings of the Seventh Symposium on Oper-
ating System Principles, ACM-SIGOPS, December 1979.
[16] Brinch Hansen, P., ‘‘The Programming Language Concurrent Pascal,’’ IEEE Transactions on Software En-
gineering, vol. SE-1, pp. 199-207, June 1975.
[17] J-P. Briot and A. Yonezawa, ‘‘Inheritance and Synchronization in Concurrent OOP,’’Proc.ECOOP’87, Paris,
France, June 1987,BIGRE, no. 54, pp. 35-43, June 1987.
126 References
[18] J.P. Briot, “Actalk: A Testbed for Classifying and Designing Actor Languages in the Smalltalk-80 Environ-
ment,” inProc. ECOOP’89, ed. S. Cook, British Computer Society Workshop Series, Cambridge University
Press, 1989.
[19] R.H. Campbell and A.N. Habermann, ‘‘The Specification of Process Synchronization by Path Expressions,’’
LNCS, vol. 16, pp. 89-102, Springer-Verlag, New York, 1974.
[20] L. Cardelli and P. Wegner, ‘‘On Understanding Types, Data Abstraction, and Polymorphism,’’ ACM Com-
puting Surveys, vol. 17, no. 4, pp. 471-523, December 1985.
[21] D. Caromel, “Concurrency and Reusability: From Sequential to Parallel,” JOOP, Sept./Oct. 1990.
[22] R.L. Cook, F.L. Rawson III, J.A. Tunkel and R.L. Williams,”Writing an Operating System/2 Application,”
IBM Systems Journal, vol. 27, no. 2, pp. 134-157, 1988.
[23] Courtois P., Heymans F. and Parnas D., ‘‘Concurrent Control with Readers and Writers,’’ Communications
of the ACM, vol. 14, no. 10, pp. 667-668, Oct. 1971.
[24] W. Cook, ‘‘A Proposal for Making Eiffel Type-Safe,’’ inProc. ECOOP’89, ed. S. Cook, British Computer
Society Workshop Series, Cambridge University Press, 1989.
[25] B.J. Cox,Object Oriented Programming: An Evolutionary Approach, Addison-Wesley, 1986.
[26] S. Danforth and C. Tomlinson, ‘‘Type Theories and Object-Oriented Programming,’’ ACM Computing Sur-
veys, vol. 20, no. 1, pp. 29-72, March 1988.
[27] D. Decouchant, S. Krakowiak, M. Meysembourg, M. Rivelli and Rousset de Pina, ‘‘A Synchronization
Mechanism for Typed Objects in a Distributed System,’’ SIGPLAN Notices, vol. 24, no. 4, ACM, April 1989.
[28] L. P. Deutsch, ‘‘Reusability in the Smalltalk-80 Programming system,’’ inIEEE Tutorial on Software reus-
ability 1987.
[29] L. P. Deutsch, ‘‘Levels of reuse in the Smalltalk-80 programming system,’’ inTutorial: Software reusability,
ed. P. Freeman, IEEE Computer Society Press, 1987.
[30] L.P. Deutsch, ‘‘Design Reuse and Frameworks in the Smalltalk-80 system,’’ inSoftware Reusability, ed. T.J.
Biggerstaff and A.J. Perlis, vol. 2, pp. 57-71, ACM Press, 1989.
[31] U. Engberg and M. Nielsen, ‘‘A Calculus of Communicating Systems with Label Passing,’’ DAIMI PB-208,
University of Aarhus, 1986.
[32] W.M. Gentleman, “Message Passing Between Sequential Processes: the Reply Primitive and the Administra-
tor Concept,” Software-Practice and Experience, vol. 11, pp. 435-466, 1981.
[33] S.J. Gibbs, D.C. Tsichritzis, E. Casais, O.M. Nierstrasz and X. Pintado, ‘‘Class Management for Software
Communities,’’ Communications of the ACM, vol. 33, no. 9, pp. 90-103, Sept 1990.
[34] A. Goldberg and D. Robson,Smalltalk-80: The Language and its Implementation, Addison-Wesley, 1983.
[35] M. Gordon ,The denotational description of programming languages, springer verlag, 1979.
[36] M. Hennessy and R. Milner, ‘‘Algebraic Laws for Nondeterminism and Concurrency,’’ Journal of the ACM,
vol. 32, no. 1, pp. 137-161, Jan 1985.
[37] C.A.R Hoare, ‘‘Proof of correcteness of data representations,’’ Acta Informatica, vol. 1, pp. 271-281, Feb.
1972.
[38] C.A.R. Hoare, “Monitors : An Operating System Structuring Concept,” CACM, vol. 17, no. 10, pp. 549-557,
ACM, October 1974.
[39] C.A.R. Hoare, “Communicating Sequential Processes,” CACM, vol. 21, no. 8, pp. 666-677, Aug 1978.
[40] R. E. Johnson and B. Foote, ‘‘Designing Reusable Classes,’’ JOOP, pp. 22-35, June/July 1988.
[41] D. G. Kafura and K. H. Lee, ‘‘Inheritance in Actor Based Concurrent Object-Oriented Languages,’’ inProc.
ECOOP’89, ed. S. Cook, British Computer Society Workshop Series, Cambridge University Press, 1989.
References 127
[42] D. Konstantas, O.M. Nierstrasz and M. Papathomas, ‘‘An Implementation of Hybrid,’’ inActive Object En-
vironments,Centre Universitaire d’Informatique, University of Geneva, ed. D. Tsichritzis, pp. 61-105, 1988.
[43] S. Krakowiak et al.,”Design and Implementation of an Object-Oriented, Strongly Typed Language for Dis-
tributed Applications,” JOOP, September/October 1990, pp. 11-22.
[44] B.W. Lampson and D.D. Redell, ‘‘Experience with Processes and Monitors in Mesa,’’ Communications, vol.
23, no. 2, pp. 105-117, ACM, 1980.
[45] K.G. Larsen, ‘‘A Context Dependent Bisimulation between Processes,’’ Theoretical Computer Science, no.
49, pp. 185-215, 1987.
[46] K.G. Larsen, ‘‘Proof Systems for Hennessy-Milner Logic with Recursion,’’ inProceedings CAAP ’88, ed.
M. Dauchet, M. Nivat, LNCS 299, pp. 215-230, Springer-Verlag, Nancy, March 1988.
[47] H. Lieberman, ‘‘Using Prototypical Objects to Implement Shared Behavior in Object Oriented Systems,’’
ACM SIGPLAN Notices, Proceedings OOPSLA ’86, vol. 21, no. 11, pp. 214-223, Nov 1986.
[48] B. Liskov, A. Snyder, R. Atkinson and C. Schaffert, ‘‘Abstraction Mechanisms in CLU,’’ CACM, vol. 20,
no. 8, pp. 564-576, Aug 1977.
[49] B. Liskov and S. Zilles, ‘‘Programming with Abstract Data Types,’’ Proceedings of the ACM Symposium on
Very High Level Languages, SIGPLAN Notices, vol. 9, no. 4, pp. 50-59, 1974.
[50] B. Liskov, M. Herlihy and L. Gilbert, ‘‘Limitations of Synchronous Communication with Static Process
Structure in Languages for Distributed Computing,’’ inProceedings of the 13th ACM POPL, St. Petersburg,
Florida, 1986.
[51] B. Liskov, ‘‘Distributed Programming in Argus,’’ ACM Communications, vol. 31, no. 3, pp. 300-313, March
1988.
[52] A. Lister, ‘‘The Problem of Nested Monitor Calls,’’ ACM Operating Systems Review, pp. 5-7, Jul. 1977.
[53] P. Maes, ‘‘Computational Reflection,’’ Technical Report 87-2, Artificial Inteligence Laboratory, Vrije Uni-
versity Brussels, 1987.
[54] P. Maes, ‘‘Concepts and Experiments in Computational Reflection,’’ in .Proc. OOPSLA’87, SIGPLAN No-
tices, vol. 22, no. 12, Dec. 1987.
[55] S. Matsuoka, K. Wakita and A. Yonezawa,Analysis of Inheritance Anomaly in Concurrent Object-Oriented
Languages (Extended Abstract), To appear, SIGPLAN Notices, Proceedings of OOPSLA/ECOOP’90 work-
shop on Object-Based Concurrent Systems.
[56] B. Meyer,Object-oriented Software Construction, Prentice Hall, New York, 1988.
[57] B. Meyer, ‘‘Reusability: The Case for Object-Oriented Design,’’ IEEE Software, vol. 4 , no. 2, pp. 50 - 64,
March 1987.
[58] R. Milner,Communication and Concurrency, Prentice Hall International Series in Computer Science, 1989.
[59] R. Milner, J. Parrow and D. Walker, ‘‘A Calculus of Mobile Processes, Part I and II,’’ Report ECS-LFCS-
89-85 and -86, Laboratory for Foundations of Computer Science, Computer Science Department, University
of Edinburgh, 1989.
[60] J.E.B. Moss and W.H. Kohler, “Concurrency Features for the Trellis/Owl Language,” Proceedings of
ECOOP ‘87,BIGRE, no. 54, pp. 223-232, June 1987.
[61] C. Neusius,Synchronizing Actions, LNCS, 512, pp. 118-132, Springer Verlag, July 1991, Proceedings of
ECOOP’91, Geneva, Switzerland.
[62] O. Nierstrasz, ‘‘Active Objects in Hybrid,’’Proc. OOPSLA’87, SIGPLAN Notices, vol. 22, no. 12, pp. 243-
253, Dec. 1987.
[63] O.M. Nierstrasz, ‘‘Triggering Active Objects,’’ inObjects and Things, ed. D.C. Tsichritzis, pp. 43-78, Centre
Universitaire d’Informatique, University of Geneva, March 1987.
128 References
[64] O.M. Nierstrasz, “A Survey of Object-Oriented Concepts,” in Object-Oriented Concepts, Databases and Ap-
plications, ed. W. Kim and F. Lochovsky, pp. 3-21, ACM Press, 1989.
[65] O.M. Nierstrasz, ‘‘A Guide to Specifying Concurrent Behavior with Abacus,’’ inObject Management, ed.
D.C. Tsichritzis, pp. 267-293, Centre Universitaire d’Informatique, University of Geneva, July 1990.
[66] O.M. Nierstrasz and M. Papathomas, ‘‘Viewing Objects as Patterns of Communicating Agents.,’’ ACM SIG-
PLAN Notices, vol. 25, no. 10, ACM Press, October 1990.
[67] O.M. Nierstrasz and M. Papathomas, ‘‘Towards a Type Theory for Active Objects,’’ inObject Management,
Centre Universitaire d’Informatique, University of Geneva, ed. D. Tsichritzis, pp. 295-304, 1990, To appear,
SIGPLAN Notices, Proceedings of OOPSLA/ECOOP’90 workshop on Object-Based Concurrent Systems..
[68] M. Papathomas and D. Konstantas, ‘‘Integrating Concurrency and Object-Oriented Programming: An Eval-
uation of Hybrid,’’ inObject Management, Centre Universitaire d’Informatique, University of Geneva, ed.
D. Tsichritzis, pp. 229-244, 1990.
[69] M. Papathomas, ‘‘Concurrency Issues in Object-Oriented Languages,’’ inObject Oriented Development ,
Centre Universitaire d’Informatique, University of Geneva, ed. D. Tsichritzis, pp. 207-245, 1989.
[70] D.L. Parnas, ‘‘A Technique for Software Module Specification with Examples,’’ CACM, vol. 15, no. 5, pp.
330-336, May 1972.
[71] D.L. Parnas, ‘‘On the Criteria to be Used in Decomposing Systems into Modules,’’ CACM, vol. 15, no. 12,
pp. 1053-1058, December 1972.
[72] D.L. Parnas, ‘‘The Non-Problem of Nested Monitor Calls,’’ ACM Operating Systems Review, vol. 12, no. 1,
pp. 12-14, 1978.
[73] G. A. Pascoe, ‘‘Encapsulators: A New Software Paradigm in Smalltalk 80,’’ inproc. of OOPSLA ’86, SIG-
PLAN, ACM, Sept. 1986.
[74] J.E. Stoy,”Denotational Semantics: The Scott-Stratchey Approach to Programming Language Theory,”, MIT
Press, 1979.
[75] A. Snyder, ‘‘Encapsulation and Inheritance in Object-Oriented Programming Languages,’’ ACM SIGPLAN
Notices, vol. 21, no. 11, pp. 38-45, Nov 1986.
[76] B. Stroustrup,The C++ Programming Language, Addison-Wesley, 1986.
[77] T.J. Teorey and T.B. Pinkerton, ‘‘A Comparative Analysis of Disk Scheduling Policies,’’ CACM, vol. 15,
no. 3, pp. 177-184, March 1972.
[78] R. D. Tennet, ‘‘The Denotational Semantics of Programming Languages,’’ CACM, vol. 19, no. 8, ACM, Au-
gust 1976.
[79] B. Thomsen, ‘‘A Calculus of Higher Order Communicating Systems,’’ 16th Symposium on Principles of Pro-
gramming Languages, pp. 143-154, Austin, Texas, Jan 11-13, 1989.
[80] C. Tomlinson and V. Singh, ‘‘Inheritance and Synchronization with Enabled Sets,’’ ACM SIGPLAN Notic-
es, Proceedings OOPSLA ’89, vol. 24, no. 10, pp. 103-112, Oct 1989.
[81] A. Tripathi and M. Aksit, “Communication, Scheduling, and Resource Management in SINA,” JOOP, pp. 24-
36, Nov/Dec 1988.
[82] D. Tsichritzis and O.M. Nierstrasz, ‘‘Application Development Using Objects,’’ Proc EUROINFO’88, pp.
15-23, North-Holland, 1988.
[83] F.W. Vaandrager, ‘‘Process Algebra Semantics of POOL,’’ inApplications of Process Algebra, ed. J.C. Ba-
eten, Cambridge Tracts in Theoretical Computer Science 17, pp. 173-236, Cambridge University Press, 1990.
[84] J. Van Den Bos and C. Laffra, “PROCOL: A Parallel Object Language with Protocols,” ACM SIGPLAN No-
tices, Proceedings OOPSLA ’89, vol. 24, no. 10, pp. 95-102, Oct 1989.
References 129
[85] D. Walker, ‘‘π-calculus Semantics of Object-Oriented Programming Languages,’’ Report ECS-LFCS-90-
122, Laboratory for Foundations of Computer Science, Computer Science Department, University of Edin-
burgh, Oct. 1990.
[86] T. Watanabe and A. Yonezawa , “Reflection in an Object Oriented Concurrent Language,” ACM SIGPLAN
Notices, vol. 23, no. 11, pp. 306-315, 1988.
[87] P. Wegner, ‘‘Dimensions of Object-Based Language Design,’’ inProceedings OOPSLA ’87, SIGPLAN No-
tices, vol. 22, pp. 168-182, ACM, Orlando, Florida, December 1987.
[88] P. Wegner and S. B. Zdonik, ‘‘Inheritance as an Incremental Modification Mechanism or What Like Is and
Isn’t Like,’’ in Proceedings ECOOP’88, Lecture Notes in Computer Science, vol. 322, pp. 55-77, Springer
Verlag, 1988.
[89] R. J. Wirfs-Brock and R.E. Johnson, ‘‘Surveying Current Research in Object-Oriented Design,’’ Communi-
cations of the ACM, vol. 33, no. 9, pp. 104-123, Sept. 1990.
[90] Y. Yokote and M. Tokoro, “Concurrent Programming in ConcurrentSmalltalk,” inObject-Oriented Concur-
rent Programming, ed. M. Tokoro, pp. 129-158, The MIT press, Cambridge, Massachusetts, 1987.
[91] Y. Yokote and M. Tokoro, ‘‘Experience and Evolution of ConcurrentSmalltalk,’’ inProceedings OOPSLA
’87, SIGPLAN Notices, vol. 22, pp. 168-182, ACM, Orlando, Florida, December 1987.
[92] A. Yonezawa, E. Shibayama, T. Takada and Y. Honda, “Modelling and Programming in an Object-Oriented
Concurrent Language ABCL/1,” inObject-Oriented Concurrent Programming, ed. M. Tokoro, pp. 55-89,
The MIT Press, Cambridge, Massachusetts, 1987.