Вы находитесь на странице: 1из 161

LES LANGAGES OBJETS

Principes de base,
techniques de programmation

Michel Beaudouin-Lafon
Armand Colin 1992
Table des matires
Chapitre 1 - INTRODUCTION ..............................................1
1.1 Le champ des langages...............................................1
1.2 Historique...................................................................8
1.3 Plan du livre .............................................................12

Chapitre 2 - PRINCIPES DE BASE......................................13


2.1 Classes et instances....................................................14
2.2 Mthodes et envoi de message ..................................17
2.3 Lhritage ................................................................18
2.4 Lhritage multiple...................................................22
2.5 Le polymorphisme ...................................................24
2.6 Les mtaclasses.........................................................28

Chapitre 3 - LANGAGES OBJETS TYPS.......................31


3.1 Classes, objets, mthodes...........................................33
3.2 Hritage....................................................................39
3.3 Hritage multiple......................................................44
3.4 Liaison dynamique...................................................48
3.5 Rgles de visibilit ....................................................52
3.6 Mcanismes spcifiques............................................56
3.7 Conclusion ...............................................................60

Chapitre 4 - SMALLTALK ET SES DRIVS....................61


4.1 Tout est objet............................................................64
4.2 Classes, instances, messages.......................................65
4.3 Hritage....................................................................69
4.4 Les structures de contrle .........................................74
4.5 Mtaclasses...............................................................81
4.6 Les drivs de Smalltalk............................................87
4.7 Conclusion ...............................................................92

Chapitre 5 - PROTOTYPES ET ACTEURS..........................93


5.1 Langages de prototypes............................................93
5.2 Langages dacteurs.................................................104

Chapitre 6 - PROGRAMMER AVEC DES OBJETS ...........117


6.1 Identifier les classes ................................................118
6.2 Dfinir les mthodes...............................................125
6.3 Rutiliser les classes ................................................132
6.4 Exemple : les Tours de Hanoi.................................136
6.5 Conclusion .............................................................140

Bibliographie.....................................................................141

Index.................................................................................145
Avant-propos
Ce livre a pour objectif de prsenter les langages objets et la
programmation par objets d'une manire gnrale et nanmoins
prcise. Le nombre de langages objets existant aujourd'hui et
leur diversit interdisent une tude exhaustive dans un ouvrage
de cette taille. C'est pourquoi l'on s'est attach identifier un
nombre rduit de concepts de base, partags par de nombreux
langages, et illustrer ces concepts par des exemples concrets. Il
ne s'agit donc pas d'apprendre programmer avec un langage
objets (d'autres ouvrages, spcialiss, s'y emploient), mais de
matriser les principes de ces langages et les techniques de la
programmation par objets.

Ce livre s'adresse des lecteurs ayant une exprience de la


programmation avec des langages classiques comme Pascal et
Lisp, ou tout au moins une connaissance des principes de ces
langages. Il s'adresse donc tout particulirement des tudiants
de second et troisime cycle d'Informatique, ou d'autres
disciplines dans lesquelles la formation l'Informatique aborde
les langages de programmation volus. Ce livre s'adresse
galement aux lves des coles d'ingnieurs, aux chercheurs,
aux enseignants, et plus gnralement tous ceux qui veulent
comprendre les langages objets.
Plusieurs annes d'enseignement des langages objets au
D.E.S.S. Systme et Communication Homme-Machine de
l'Universit de Paris-Sud, et des confrences au Certificat C4
d'Informatique Applique de cette mme Universit, m'ont
conduit la prsentation des langages objets adopte dans ce
livre : dans les deux cas, le faible volume horaire interdit tout
apprentissage d'un langage particulier et invite une
prsentation synthtique. Il en rsulte une grille d'analyse des
langages objets, largement maille d'exemples, dont
l'ambition est de permettre au lecteur d'aborder la program-
mation avec un langage objets avec une vision claire et saine
de l'univers de ces langages.

Plusieurs personnes ont contribu rendre ce livre plus clair


et, je l'espre, facile d'accs : Thomas Baudel, Jean Chassain,
Stphane Chatty, Marc Durocher, Solange Karsenty ont relu des
versions prliminaires de cet ouvrage et apport des commen-
taires constructifs ; les membres du groupe Interfaces Homme-
Machine du Laboratoire de Recherche en Informatique, par leur
exprience quotidienne de la programmation par objets, ont
permis tout la fois de mettre en vidence les ralits pratiques
de l'utilisation des langages objets et de mettre l'preuve un
certain nombre d'ides prsentes dans ce livre. Marie-Claude
Gaudel a galement contribu clarifier les notions lies au
typage dans les langages de programmation en gnral et dans
les langages objets en particulier. Enfin, mon frre Emmanuel
a ralis l'ensemble des figures de cet ouvrage, et je lui en suis
infiniment reconnaissant.
Chapitre 1

INTRODUCTION
Les langages objets sont apparus depuis quelques annes
comme un nouveau mode de programmation. Pourtant la
programmation par objets date du milieu des annes 60 avec
Simula, un langage cr par Ole Dahl et Kristen Nygaard en
Norvge et destin programmer des simulations de processus
physiques. Bien que de nombreux travaux de recherche aient
eu lieu depuis cette poque, lessor des langages objets est
beaucoup plus rcent. Ce livre essaie de montrer que les
langages objets ne sont pas une mode passagre, et que la
programmation par objets est une approche gnrale de la
programmation qui offre de nombreux avantages.

1.1 LE CHAMP DES LANGAGES


Situer les langages objets dans le vaste champ des langages
de programmation nest pas chose facile tant le terme dobjet
recouvre de concepts diffrents selon les contextes. Nous
prsentons ici plusieurs classifications des langages et situons les
langages objets dans ces diffrentes dimensions.
2 Les langages objets

Classification selon le mode de programmation

Cette classification prsente les principaux modles de


programmation qui sont utiliss aujourdhui, cest--dire les
principaux modles par lesquels on peut exprimer un calcul.

La programmation imprative, la plus ancienne, correspond


aux langages dans lesquels lalgorithme de calcul est dcrit
explicitement, laide dinstructions telles que laffectation, le
test, les branchements, etc. Pour sexcuter, cet algorithme
ncessite des donnes, stockes dans des variables auxquelles
le programme accde et quil peut modifier. La formule de
Niklaus Wirth dcrit parfaitement cette catgorie de langages :
programme = algorithme + structure de donnes.
On classe dans cette catgorie les langages dassemblage,
Fortran, Algol, Pascal, C, Ada. Cette catgorie de langages est
la plus ancienne car elle correspond naturellement au modle
darchitecture des machines qui est la base des ordinateurs :
le modle de Von Neumann.

La programmation fonctionnelle adopte une approche


beaucoup plus mathmatique de la programmation. Fonde
sur des travaux assez anciens sur le lambda-calcul et
popularise par le langage Lisp, la programmation
fonctionnelle supprime la notion de variable, et dcrit un
calcul par une fonction qui sapplique sur des donnes
dentres et fournit comme rsultat les donnes en sortie. De
fait, ce type de programmation est plus abstrait car il faut
dcrire lalgorithme indpendamment des donnes. Il existe
peu de langages purement fonctionnels ; beaucoup intro-
duisent la notion de variable pour des raisons le plus souvent
pratiques, car labstraction complte des donnes conduit
souvent des programmes lourds crire. Parmi les langages
fonctionnels, il faut citer bien sr Lisp et ses multiples
incarnations (CommonLisp, Scheme, Le_Lisp, etc.), ainsi que
ML.

La programmation logique, ne dune approche galement


lie aux mathmatiques, la logique formelle, est fonde sur la
Introduction 3

description dun programme sous forme de prdicats. Ces


prdicats sont des rgles qui rgissent le problme dcrit ;
lexcution du programme, grce linfrence logique,
permet de dduire de nouvelles formules, ou de dterminer si
une formule donne est vraie ou fausse partir des prdicats
donns. Linfrence logique est tout fait similaire aux
principes qui rgissent la dmonstration dun thorme
mathmatique laide daxiomes et de thormes connus. Le
plus clbre des langages logiques est Prolog.

La programmation par objets est-elle une nouvelle catgorie


dans cette classification ? Il est difficile de rpondre cette
question. La programmation par objets est proche de la
programmation imprative : en effet, l o la programmation
imprative met laccent sur la partie algorithmique de la
formule de Wirth, la programmation par objets met laccent sur
la partie structure de donnes. Nanmoins, ceci nest pas
suffisant pour inclure la programmation par objets dans la
programmation imprative, car lapproche des langages objets
sapplique aussi bien au modle fonctionnel ou logique quau
modle impratif.

Classification selon le mode de calcul

Cette classification complte la prcdente en distinguant deux


modles dexcution dun calcul :

Les langages squentiels correspondent une excution


squentielle de leurs instructions selon un ordre que lon peut
dduire du programme. Ces langages sont aujourdhui les
plus rpandus, car ils correspondent larchitecture classique
des ordinateurs dans lesquels on a une seule unit de
traitement (modle de Von Neumann). Les langages objets
sont pour la plupart squentiels.

Les langages parallles permettent au contraire plusieurs


instructions de sexcuter simultanment dans un programme.
Lessor de la programmation parallle est d la disponibilit
de machines architecture parallle. La programmation
4 Les langages objets

parallle ncessite des langages spcialiss car les langages


usuels ne fournissent pas les primitives de communication et
de synchronisation indispensables. Or il savre que le modle
gnral de la programmation par objets est facilement
paralllisable. Une classe de langages objets, les langages
dacteurs, sont effectivement des langages parallles.

Classification selon le typage

Cette classification considre la notion de type qui, dans les


langages de programmation, est destine apporter une scurit
au programmeur : en associant un type chaque expression
dun programme, on peut dterminer par une analyse statique,
cest--dire en observant le texte du programme sans lexcuter,
si le programme est correct du point de vue du systme de
types. Cela permet dassurer que le programme ne provoquera
pas derreur lexcution en essayant, par exemple, dajouter
un boolen un entier.

Dans un langage typage statique, on associe, par une


analyse statique, un type chaque expression du programme.
Cest le systme de types le plus sr, mais aussi le plus
contraignant. Pascal est lexemple typique dun langage
typage statique.

Dans un langage fortement typ, lanalyse statique permet de


vrifier que lexcution du programme ne provoquera pas
derreur de type, sans pour autant tre capable dassocier un
type chaque expression. Ceci signifie que les types devront
ventuellement tre calculs lexcution pour contrler
celle-ci. Les langages qui offrent le polymorphisme
paramtrique (ou gnricit), comme ADA, sont fortement
typs. La plupart des langages objets typs sont fortement
typs, et notamment Simula, Modula3 et C++.

Dans un langage faiblement typ, on ne peut assurer, par la


seule analyse statique, que lexcution dun programme ne
provoquera pas derreur lie au systme de types. Il est donc
ncessaire de calculer et de contrler les types lexcution,
Introduction 5

ce qui justifie lappellation de langage typage dynamique.


Parmi les langages objets, Eiffel est faiblement typ car une
partie du contrle de types doit tre ralise lexcution.

Dans un langage non typ, la notion de type nexiste pas, et il


ne peut donc y avoir de contrle sur la validit du programme
vis--vis des types. Ainsi, Lisp est un langage non typ, de
mme que le langage objets Smalltalk.

La notion de type apporte une scurit de programmation


indispensable dans la ralisation de gros systmes. De plus,
comme nous allons le voir, elle permet de rendre lexcution
des programmes plus efficace. Cest donc une notion
importante, et lon peut constater que les langages objets
couvrent une grande partie de la classification ci-dessus. Cest
ce critre qui va nous servir structurer la suite de ce livre en
distinguant dun ct les langages typs (fortement ou
faiblement), dautre part les langages non typs. De nombreux
travaux sont consacrs actuellement ltude des systmes de
types dans les langages objets car le concept dhritage, qui est
lun des fondements des langages objets, ncessite des
systmes de types qui nentrent pas dans les cadres tudis
jusqu prsent.

Classification selon le mode dexcution

Cette classification porte sur la faon dont lexcution du


programme est ralise. Le mode dexcution nest pas
proprement parler une caractristique dun langage, mais une
caractristique de limplmentation dun langage.

Les langages interprts permettent lutilisateur dentrer des


expressions du langage et de les faire excuter
immdiatement. Cette approche offre lavantage de pouvoir
tester et modifier rapidement un programme au dtriment de
la vitesse dexcution. Outre la vitesse dexcution, les
langages interprts ont gnralement pour inconvnient
dtre moins srs, car de nombreux contrles smantiques
sont raliss au fur et mesure de linterprtation et non dans
6 Les langages objets

une phase prliminaire de compilation. Beaucoup de langages


objets sont interprts, et tirent avantage de cette apparente
faiblesse pour donner une plus grande souplesse lexcution
des programmes. Ainsi, une modification ponctuelle dun
programme peut avoir des effets (contrls) sur lensemble de
lexcution, ce qui permet notamment de construire des
environnements sophistiqus pour la mise au point des
programmes.

Les langages compils ncessitent une phase de compilation


avant de passer lexcution proprement dite dun
programme. Le but de la compilation est essentiellement de
produire du code directement excutable par la machine, donc
plus efficace. Pour cela, le compilateur utilise en gnral les
informations qui lui sont fournies par le systme de types du
langage. Cest ainsi que la plupart des langages typs sont
compils. De manire gnrale, les langages interprts sont
plus nombreux que les langages compils car la ralisation
dun compilateur est une tche complexe, surtout si lon veut
engendrer du code machine efficace. Les langages objets
nchappent pas cette rgle, et il existe peu de langages
objets compils.

Les langages semi-compils ont les caractristiques des


langages interprts mais, pour une meilleure efficacit, ils
utilisent un compilateur de manire invisible pour lutilisateur.
Ce compilateur traduit tout ou partie du programme dans un
code intermdiaire ou directement en langage machine. Si le
compilateur engendre un code intermdiaire, cest un
interprteur de ce code qui ralisera lexcution du
programme. Les langages objets considrs comme
interprts sont souvent semi-compils, comme Smalltalk ou le
langage de prototypes Self.

Classification selon la modularit

Cette dernire classification analyse la faon dont les langages


permettent au programmeur de raliser des modules et
dencapsuler les donnes. La modularit et lencapsulation
Introduction 7

assurent une plus grande scurit de programmation et


fournissent la base de la rutilisation.

Absence de modularit : le programmeur doit, par des


conventions de programmation et de nommage, prendre en
charge la modularit. Cest notamment le cas de Pascal qui
oblige donner des noms diffrents toutes les variables,
procdures et fonctions globales, et ne permet pas de cacher
des dfinitions autrement que par les rgles de visibilit
(procdures imbriques), ce qui est insuffisant. Le langage C
offre une modularit selon le dcoupage du programme en
fichiers, en permettant de dclarer des variables ou fonctions
prives un fichier. En revanche, il noffre pas la possibilit
dimbrication des procdures et fonctions.

Modularit explicite : certains langages offrent la notion de


module comme concept du langage, que lon peut composer
avec dautres notions. Par exemple, en Ada, la notion de
package permet dimplmenter un module, et se combine
avec la gnricit pour autoriser la dfinition de modules
gnriques (paramtrs par des types).

Modularit implicite : les langages objets fournissent une


modularit que lon peut qualifier dimplicite dans la mesure
o celle-ci ne fait pas appel des structures particulires du
langage. Au contraire, la notion de module est implicite et
indissociable de celle de classe.

La programmation par objets est une forme de program-


mation modulaire dans laquelle lunit de modularit est
fortement lie aux structures de donnes du langage. Par
comparaison, le langage Ada offre une modularit beaucoup
plus indpendante des structures de donnes et de traitement du
langage. La modularit est souvent considre comme un atout
important pour la rutilisation des programmes. De ce point de
vue, les langages objets permettent une rutilisation bien plus
importante que la plupart des autres langages.
8 Les langages objets

La programmation par objets comme un style

De ce tour dhorizon, il faut conclure que la programmation


par objets est plus une approche gnrale de la programmation
quun type facilement classable. De fait, on voit aujourdhui de
nombreuses extensions objets des langages existant : Pascal
Objet, Lisp Objet, Cobol Objet, etc. Si certaines de ces extensions
ne sont pas toujours un succs, il est un fait que les principes de
la programmation par objets sont applicables dans un grand
nombre de contextes.

1.2 HISTORIQUE
La figure 1 prsente la gnalogie des principaux langages
objets. On y distingue deux ples autour des langages Simula et
Smalltalk.

La famille Simula

Le langage Simula est considr comme le prcurseur des


langages objets. Dvelopp dans les annes 60 pour traiter des
problmes de simulation de processus physiques (do son
nom), Simula a introduit la notion de classe et dobjet, la notion
de mthode et de mthode virtuelle. Ces concepts restent la
base des langages objets typs et compils, comme on le verra
en dtail dans le chapitre 3. Simula a t cr dans la ligne du
langage Algol, langage typ de lpoque dont Pascal sest
galement inspir.

Les langages de la famille Simula sont des langages impratifs


typs et gnralement compils. Lintrt dun systme de types
est de permettre un plus grand nombre de contrles smantiques
lors de la compilation, et dviter ainsi des erreurs qui ne se
manifesteraient qu lexcution. Typage et compilation sont
deux concepts indpendants : on peut imaginer des langages
typs interprts et des langages non typs compils. Cest
nanmoins rarement le cas, car les informations dduites du
Introduction 9

Algol Lisp
1960

Simula

1970 Pascal Planner


C Smalltalk

Plasma

1980 Modula2 Flavors


ACT1
C++ Objective-C ObjVlisp
Object
Pascal Beta Eiffel ABCL /1
Modula3 Self CLOS ACT2
1990

Figure 1 - Gnalogie des principaux langages objets

typage permettent de gnrer du code plus efficace, ce qui


encourage compiler les langages typs.

Simula a inspir nombre de langages objets. Certains dentre


eux sont maintenant largement plus connus et rpandus que
Simula, comme C++ et Eiffel. Plusieurs langages ont t conus
en ajoutant des concepts des langages objets un langage
existant. Ainsi, Classcal et son descendant Object Pascal ajoutent
des classes au langage Pascal, Modula3 est une rvision majeure
de Modula2 incluant des objets, C++ est construit partir de C.
Une telle approche prsente avantages et inconvnients : il est
commode de prendre un langage existant aussi bien pour les
concepteurs que pour les utilisateurs car cela vite de tout
rinventer ou de tout rapprendre. Dun autre ct, certains
aspects du langage de base peuvent se rvler nfastes pour
ladjonction de mcanismes des langages objets.

La famille Smalltalk

Dans les annes 70, sous limpulsion dAlan Kay, ont


commenc aux laboratoires Xerox PARC des recherches qui ont
conduit au langage Smalltalk, considr par beaucoup comme le
10 Les langages objets

prototype des langages objets. De fait, cest Smalltalk plutt


que Simula qui est lorigine de la vague des langages objets
depuis les annes 80.

Smalltalk sinspire de Simula pour les concepts de classes,


dobjets et de mthodes, mais adopte une approche influence
par Lisp pour ce qui concerne limplmentation : Smalltalk est
un langage semi-compil dans lequel tout est dcid lors de
lexcution. Comme dans Lisp, la souplesse due laspect
interprt de lexcution est largement exploite par le langage.

Dun point de vue conceptuel, Smalltalk introduit la notion de


mtaclasse qui nest pas prsente dans Simula. Cette notion
permet de donner une description mta-circulaire du langage de
telle sorte que lon peut raliser assez simplement un
interprteur de Smalltalk en Smalltalk. Cet aspect mta-
circulaire est galement prsent dans Lisp, et dans de nombreux
langages interprts. Dans le cas de Smalltalk, les mtaclasses
sont accessibles lutilisateur de faon naturelle, et permettent
de nombreuses facilits de programmation. Lintroduction du
modle mta-circulaire dans Smalltalk date de la premire
version du langage (Smalltalk-72). Les versions suivantes
(Smalltalk-76 et Smalltalk-80) ont affin, amlior et enrichi ce
modle. Dautres langages inspirs de Smalltalk sont alls plus
loin dans cette direction, notamment ObjVLisp et Self.

La meilleure preuve de la puissance de Smalltalk est


lensemble des programmes raliss en Smalltalk, et lintense
activit de recherche autour du langage, de ses concepts ou de
ses langages drivs. Parmi les ralisations, il faut noter
lenvironnement de programmation Smalltalk, ralis Xerox
PARC et implment lui-mme en Smalltalk. Cet environ-
nement, qui inclut un systme dexploitation, est le premier
environnement graphique a avoir t largement diffus.

Smalltalk a inspir de nombreux langages de programmation.


Alors que Smalltalk est un langage natif, la plupart des langages
quil a inspirs sont raliss au-dessus de Lisp. Il savre que
Lisp fournit une base au-dessus de laquelle il est facile de
Introduction 11

construire des mcanismes dobjets. On peut nanmoins


regretter que dans nombre de cas le langage sous-jacent reste
accessible, ce qui donne lutilisateur deux modes de program-
mation largement incompatibles : le mode fonctionnel de Lisp
et le mode de programmation par objets. Certaines incarnations
de Lisp intgrent les notions dobjets de faon presque native,
comme Le_Lisp et CLOS (CommonLisp Object System).

Autres familles, autres langages

Si les familles Simula et Smalltalk reprsentent une grande


partie des langages objets, il existe dautres langages
inclassables, dautres familles en cours de formation.

Ainsi le langage Objective-C est un langage hybride qui


intgre le langage C avec un langage objets de type Smalltalk.
Plutt quune intgration, on peut parler dune coexistence
entre ces deux aspects, car on passe explicitement dun univers
lautre par des dlimiteurs syntaxiques. Les entits dun univers
peuvent tre transmises lautre, mais elles sont alors des objets
opaques que lon ne peut manipuler. Lintrt de cette
approche est de donner lutilisateur un environnement
compil et typ (composante C) et un environnement interprt
non typ (composante Smalltalk). Parmi les logiciels raliss en
Objective-C, le plus connu est certainement Interface Builder,
lenvironnement de construction dapplications interactives de
la machine NeXT.

Une autre famille est constitue par les langages de


prototypes. Ces langages, au contraire des langages objets
traditionnels, ne sont pas fonds sur les notions de classes et
dobjets, mais uniquement sur la notion de prototype. Un
prototype peut avoir les caractristiques dune classe, ou dun
objet, ou bien des caractristiques intermdiaires entre les deux.
Dune certaine faon, ces langages poussent le concept des
objets dans ses derniers retranchements et permettent dexplorer
de nouveaux paradigmes de programmation.
12 Les langages objets

Une dernire famille est constitue de langages parallles


appels langages dacteurs. Dans un programme crit avec un
tel langage, chaque objet, appel acteur, est un processus qui
sexcute de faon autonome, mettant et recevant des messages
dautres acteurs. Lorsquun acteur envoie un message un
autre acteur, il peut continuer son activit, sans se soucier de ce
quil advient du message. Le paralllisme est donc introduit par
une simple modification du mode de communication entre les
objets. Compar aux modles de paralllisme mis en uvre dans
dautres langages, comme les tches de Ada, la simplicit et
llgance du modle des acteurs est surprenante. Cela fait des
langages dacteurs un moyen privilgi dexploration du
paralllisme.

1.3 PLAN DU LIVRE


Ce livre a pour but de prsenter les principes fondamentaux
des langages objets et les principales techniques de
programmation par objets. Il ne prtend pas apprendre
programmer avec tel ou tel langage objets. cet effet, les
exemples sont donns dans un pseudo-langage la syntaxe
proche de Pascal. Ceci a pour but une prsentation plus
homogne des diffrents concepts.

Le prochain chapitre prsente les principes gnraux qui sont


la base de la programmation par objets. Les trois chapitres
suivants prsentent les grandes familles de langages objets : les
langages objets typs, cest--dire les langages de la famille de
Simula (chapitre 3) ; les langages objets non typs, et en
particulier Smalltalk (chapitre 4) ; les langages de prototypes et
les langages dacteurs (chapitre 5). Le dernier chapitre prsente
un certain nombre de techniques usuelles de la programmation
par objets et une bauche de mthodologie.

Une connaissance des principes de base des langages de


programmation en gnral et de Pascal en particulier est
suppose dans lensemble de louvrage. Les chapitres 3 et 4
Introduction 13

sont indpendants. Les lecteurs qui prfrent Lisp Pascal


peuvent lire le chapitre 4 avant le chapitre 3.
Chapitre 2

PRINCIPES DE BASE
Un langage objets utilise les notions de classe et dinstance,
que lon peut comparer aux notions de type et de variable dun
langage tel que Pascal. La classe dcrit les caractristiques
communes toutes ses instances, sous une forme similaire un
type enregistrement ( record Pascal). Une classe dfinit donc
un ensemble de champs. De plus, une classe dcrit un ensemble
de mthodes, qui sont les oprations ralisables sur les instances
de cette classe. Ainsi une classe est une entit autonome. Au lieu
dappliquer des procdures ou fonctions globales des
variables, on invoque les mthodes des instances. Cette
invocation est souvent appele envoi de message. De fait, on
peut considrer que lon envoie un message une instance pour
quelle effectue une opration, cest--dire pour quelle
dtermine la mthode invoquer.

On utilise souvent le terme dobjet la place dinstance. Le


terme instance insiste sur lappartenance une classe : on
parle dune instance dune classe donne. Le terme objet
rfre de faon gnrale une entit du programme (qui peut
tre une instance, mais aussi un champ, une classe, etc.).
16 Les langages objets

Lien d'hritage
Classe de Base Lien d'instanciation

Classe

Champs Objet

Mthodes

Envoi de message

Figure 2 - Illustration des notions de base

Lhritage est la dernire notion de base des langages


objets : une classe peut tre construite partir dune classe
existante, dont elle tend ou modifie la description. Ce
mcanisme de structuration est fondamental dans les langages
objets ; il est dcrit dans la section 2.3 de ce chapitre.

La figure 2 dcrit ces quatre notions de base, et introduit les


conventions que nous utiliserons dans les autres figures.

2.1 CLASSES ET INSTANCES


La notion dobjet ou instance recouvre toute entit dun
programme crit dans un langage objets qui stocke un tat et
rpond un ensemble de messages. Cette notion est comparer
avec la notion usuelle de variable : une variable stocke un tat,
mais na pas la capacit par elle-mme deffectuer des
traitements. On utilise pour cela dans les langages classiques des
sous-programmes, fonctions ou procdures. Ceux-ci prennent
des variables en paramtre, peuvent les modifier et peuvent
retourner des valeurs.
Principes de base 17

Dans un langage classique, on dfinirait par exemple un type


Pile et des procdures pour accder une pile ou la modifier :
Empiler, qui prend une pile et une valeur empiler ;
Dpiler, qui prend une pile ;
Sommet, qui prend une pile et retourne une valeur.

Cette sparation entre variables et procdures dans les


langages classiques est la source de nombreux problmes en ce
qui concerne lencapsulation : pour des raisons de scurit de
programmation, on ne souhaite pas que nimporte quelle
procdure puisse accder au contenu de nimporte quelle
variable. On est alors amen introduire la notion de module.
Un module exporte des types, des variables et des procdures.
De lextrieur, les types sont opaques : leur implmentation
nest pas accessible. On ne peut donc manipuler les variables de
ce type que par lintermdiaire des procdures exportes par le
module. lintrieur du module, limplmentation des types est
dcrite, et est utilisable par les corps des procdures.

Ainsi, on peut encapsuler la notion de pile dans un module.


Ce module exporte un type Pile, et les procdures Empiler,
Dpiler et Sommet, dont limplmentation nest pas connue de
lextrieur. Par cette technique, un utilisateur du module ne
pourra pas modifier une pile autrement que par les procdures
fournies par le module, ce qui assure lintgrit dune pile.

Le module constitue donc le moyen de regrouper types et


procdures, pour construire des types abstraits. Les langages
Clu, Ada et ML, parmi dautres, offrent de telles possibilits.
Dans les langages qui noffrent pas de modularit (Pascal, C,
Lisp etc.), le programmeur doit faire preuve dune grande
rigueur pour reproduire artificiellement, cest--dire sans aide
du langage, lquivalent de modules.

Lapproche des langages objets consiste intgrer demble


la notion de variable et de procdures associes dans la notion
dobjet. Lencapsulation est donc fournie sans mcanisme
additionnel. De mme quune variable appartient un type dans
18 Les langages objets

Pile

pile
sommet pile
sommet O
Empiler
Dpiler
Sommet

Figure 3 - La classe Pile et une instance

un langage classique, dans un langage objets un objet


appartient une classe. La classe est la fois un type et un
module : elle contient une description de type, sous forme de
champs, ainsi quun ensemble de procdures associes ce type,
appeles mthodes.

Dfinir une classe

On dfinira ainsi une classe Pile par :


un tat reprsentant la pile (tableau, liste, etc.), constitu de
champs. Pour une reprsentation par tableau, on aura ainsi
deux champs : le tableau lui-mme et lindice du sommet
courant.
la mthode Empiler, qui prend une valeur en paramtre.
la mthode Dpiler.
la mthode Sommet, qui retourne une valeur.

On cre des objets partir dune classe par le mcanisme


dinstanciation. Le rsultat de linstanciation dune classe est
un objet, appel instance de la classe (voir figure 3).
Linstanciation est similaire la cration dune variable dun
Principes de base 19

type enregistrement. Linstance cre stocke un tat constitu


dune valeur pour chacun de ses champs. Les champs sont eux-
mmes des objets. Un certain nombre de classes sont prdfinies
dans les langages, telles que la classe des entiers, des caractres,
etc.

Lencapsulation, cest--dire laccs contrl aux objets, est


assure naturellement par les classes. Bien que diffrant dun
langage lautre, comme nous le verrons, on peut considrer
dans un premier temps que les champs sont privs alors que les
mthodes sont publiques. Ceci signifie que les champs sont
visibles uniquement depuis le corps des mthodes de la classe,
alors que les mthodes sont visibles de lextrieur. Nous allons
maintenant dcrire le mcanisme dinvocation des mthodes.

2.2 MTHODES ET ENVOI DE MESSAGE


Dans les langages objets, les objets stockent des valeurs, et les
mthodes permettent de manipuler les objets. Ceci est
comparable aux langages classiques, dans lesquels les variables
stockent des valeurs et les procdures et fonctions permettent de
manipuler les variables. Mais, contrairement aux procdures et
fonctions qui sont des entits globales du programme, les
mthodes appartiennent aux classes des objets. Au lieu
dappeler une procdure ou fonction globale, on invoque une
mthode dun objet. Lexcution de la mthode est alors
ralise dans le contexte de cet objet.

Linvocation dune mthode est souvent appele envoi de


message. On peut en effet considrer que lon envoie un objet,
par exemple une pile, un message, par exemple empiler la
valeur 20 . Dans un langage classique, on appellerait la
procdure Empiler avec comme paramtres la pile elle-mme et
la valeur 20.

Cette distinction est fondamentale. En effet, lenvoi de


message implique que cest le receveur (ici la pile) qui dcide
comment empiler la valeur 20, grce la mthode dtenue par
20 Les langages objets

sa classe. Au contraire, lappel de procdure des langages


classiques implique que cest la procdure (ici Empiler) qui
dcide quoi faire de ses arguments, dans ce cas la pile et la
valeur 20. En dautres termes, la programmation imprative ou
fonctionnelle privilgie le contrle (procdures et fonctions)
alors que la programmation par objets privilgie les donnes (les
objets), et dcentralise le contrle dans les objets.

Le corps dune mthode est excut dans le contexte de


lobjet receveur du message. On a donc directement et
naturellement accs aux champs et mthodes de lobjet
receveur. Cest en fait seulement dans le corps des mthodes
que lon a accs aux parties prives de lobjet, cest--dire en
gnral ses champs (les langages diffrent sur la dfinition des
parties prives).

La dfinition conjointe des champs et des mthodes dans les


classes est la base du mcanisme dhritage, que nous allons
maintenant dcrire.

2.3 LHRITAGE
La notion dhritage est propre aux langages objets. Elle
permet la dfinition de nouvelles classes partir de classes
existantes. Supposons que lon veuille programmer le jeu des
Tours de Hanoi. On dispose de trois tours ; sur la premire sont
empils des disques de taille dcroissante. On veut dplacer ces
disques sur lune des deux autres tours en respectant les deux
rgles suivantes :
on ne peut dplacer quun disque la fois ;
on ne peut poser un disque sur un disque plus petit.

Le comportement dune tour est similaire celui dune pile :


on peut empiler ou dpiler des disques. Cependant on ne peut
empiler un disque que sil est de diamtre infrieur au sommet
courant de la tour.
Principes de base 21

Si lon utilise un langage classique qui offre lencapsulation,


on est confront lalternative suivante :
utiliser une pile pour reprsenter chaque tour, et sassurer
que chaque appel de la procdure Empiler est prcd dun
test vrifiant la validit de lempilement.
crer un nouveau module, qui exporte un type opaque Tour
et les procdures E m p i l e r , D p i l e r , et S o m m e t .
Limplmentation de Tour est une pile ; la procdure
Empiler ralise le contrle ncessaire avant dempiler un
disque. Les procdures Dpiler et Sommet appellent leurs
homologues de la pile.

Aucune de ces deux solutions nest satisfaisante. La premire


ne fournit pas dabstraction correspondant la notion de tour.
La seconde est la seule acceptable du point de vue de
labstraction mais prsente de multiples inconvnients :
Il faut crire des procdures inutiles : Dpiler du module
Tour ne fait quappeler Dpiler du module Pile ;
Si lon ajoute une fonction Profondeur dans le module Pile,
elle ne sera accessible pour lutilisateur de Tour que si lon
dfinit galement une fonction Profondeur dans le module
Tour comme on la fait pour Dpiler ;
Le problme est encore plus grave si lon dcide denlever
la fonction P r o f o n d e u r du module Pile : la fonction
Profondeur de Tour appelle maintenant une fonction qui
nexiste plus ;
Il nest pas possible daccder directement
limplmentation de la pile dans le module Tour, cause de
lencapsulation. On ne peut pas ajouter la fonction
Profondeur dans Tour sans dfinir une fonction quivalente
dans Pile.

Ce que lon cherche en ralit est la spcialisation dune pile


pour en faire une tour, en crant un lien privilgi entre les
modules Pile et Tour. Cest ce que permet lhritage par la
dfinition dune classe Tour qui hrite de Pile.
22 Les langages objets

Pile

pile
sommet
Tour
Empiler
Dpiler
Sommet
Empiler

Figure 4 - La classe Tour hrite de la classe Pile

Dfinir une classe par hritage

Lorsquune classe B hrite dune classe A, les instances de B


contiennent les mmes champs que ceux de A, et les mthodes
de A sont galement disponibles dans B. De plus, la sous-classe
B peut :
dfinir de nouveaux champs, qui sajoutent ceux de sa
classe de base A ;
dfinir de nouvelle mthodes, qui sajoutent celles hrites
de A ;
redfinir des mthodes de sa classe de base A.

Enfin, les mthodes dfinies ou redfinies dans B ont accs


aux champs et mthodes de B, mais aussi ceux de A.

Ces proprits montrent le lien privilgi qui unit B A. En


particulier, si lon ajoute des champs et/ou des mthodes A, il
nest pas ncessaire de modifier B. Il en est de mme si lon
retire des champs et/ou des mthodes de A, sauf bien sr sils
taient utiliss dans les mthodes dfinies ou redfinies dans B.
Principes de base 23

Dans notre exemple, on se bornera redfinir la mthode


Empiler, pour faire le contrle de la taille des disques et appeler
la mthode Empiler de Pile si lopration est valide (voir figure
4). Dans ce cas, on dira que lon a spcialis la classe Pile car on
a seulement redfini lune de ses mthodes. Si lon dfinissait
de nouvelles mthodes dans la classe Tour (par exemple
initialiser la tour avec N disques de taille dcroissante), on aurait
enrichi la classe Pile. Ce simple exemple montre dj que
lhritage peut servir raliser deux oprations : la
spcialisation et lenrichissement.

Larbre dhritage

Telle que nous lavons prsente, la notion dhritage induit


une fort darbres de classes : une classe A reprsente par un
nud dun arbre a pour sous-classes les classes reprsentes par
ses fils dans larbre. Les racines des arbres de la fort sont les
classes qui nhritent pas dune autre classe.
Si C hrite de B et B hrite de A, on dira par extension que C
hrite de A. On dira indiffremment :
B hrite de A
B est une sous-classe de A
B drive de A
B est une classe drive de A
A est une (la) superclasse de B
A est une (la) classe de base de B
Dans les deux dernires phrases, on emploie larticle dfini
pour indiquer que A est lantcdent direct de B dans larbre
dhritage.

Certains langages imposent une classe de base unique pour


toutes les autres, appele souvent Objet. Dans ce cas, la relation
dhritage dfinit un arbre et non une fort. Par abus de
langage, on parle dans tous les cas de larbre dhritage.
24 Les langages objets

2.4 LHRITAGE MULTIPLE


Lhritage que nous avons dfini est dit hritage simple car
une classe a au plus une classe de base. Une gnralisation de
lhritage simple, lhritage multiple, consiste autoriser une
classe hriter directement de plusieurs classes.

Ainsi si la classe B hrite de A1, A2, An, on a les proprits


suivantes :
les champs des instances de B sont lunion des champs de
A1, A2, An et des champs propres de B ;
les mthodes dfinies pour les instances de B sont lunion
des mthodes dfinies dans A1, A2, An et des mthodes
dfinies dans B. B peut galement redfinir des mthodes de
ses classes de base.

Larbre ou la fort dhritage devient alors un graphe. Pour


viter des dfinitions rcursives on interdit davoir des cycles
dans le graphe dhritage. En dautres termes, on interdit une
classe dtre sa propre sous-classe, mme indirectement.

Cette extension, apparemment simple, cache en fait de


multiples difficults, qui ont notamment trait aux problmes de
collision de noms dans lensemble des champs et mthodes
hrites. Certaines de ces difficults ne pourront tre
dveloppes que dans la description plus dtaille des chapitres
suivants.

Une difficult intrinsque de lhritage multiple est la gestion


de lhritage rpt dune classe donne : si B et C hritent de A
par un hritage simple, et D hrite de B et de C, alors D hrite
deux fois de A , par deux chemins D-B-A et D-C-A dans le
graphe dhritage (figure 5). Faut-il pour autant quune
instance de D contienne deux fois les champs dfinis dans A, ou
bien faut-il les partager ?
Principes de base 25

B C

b c

a (D.B.A) a (D.B.A, D.C.A)


b (D.B) b (D.B)
a (D.C.A) c (D.C)
c (D.C) d (D)
d (D)

Figure 5 - Deux interprtations de lhritage multiple

Selon les situations, on souhaitera lune ou lautre solution,


comme le montrent les deux exemples suivants.

Soit A la classe des engins moteur, qui contient comme


champs les caractristiques du moteur. Soit B la classe des
automobiles et C la classe des grues. D est donc la classe des
grues automobiles. Les deux interprtations de lhritage
multiple sont possibles : si lon hrite deux fois de la classe des
engins moteur, la grue automotrice a deux moteurs : lun pour
sa partie automobile, lautre pour sa partie grue. Si lon hrite
une seule fois de lengin moteur, on a un seul moteur qui sert
la fois dplacer le vhicule et manuvrer la grue.

Soit maintenant A la classe des objets mobiles, contenant les


champs position et vitesse. Soit B la classe des bateaux, qui
contient par exemple un champ pour le tonnage, et soit C la
classe des objets propulss par le vent, qui contient un champ
26 Les langages objets

pour la surface de la voile. D est alors la classe des bateaux


voile. Une instance de D a bien entendu une seule position et
une seule vitesse, et dans ce cas il faut partager les champs de A
hrits par diffrents chemins.

Lhritage multiple noffre pas de rponse satisfaisante ce


problme. La premire interprtation correspond une
composition de classes, la seconde une combinaison. Le
mcanisme de lhritage est certainement imparfait pour
capturer la fois les notions de spcialisation, denrichissement,
de composition et de combinaison. Mais lhritage nest pas le
seul moyen de dfinir des classes ! Lun des piges qui guettent
le programmeur utilisant un langage objets est la mauvaise
utilisation de lhritage. La question quil faut se poser
chaque dfinition de classe est la suivante : faut-il que B hrite
de A , ou bien B doit-elle contenir un champ qui soit une
instance de A ? B est-il une sorte de A ou bien B contient-il un
A ? Nous reviendrons au chapitre 6 sur la pratique de la
programmation par objets, et en particulier sur ces problmes.

2.5 LE POLYMORPHISME
La notion de polymorphisme recouvre la capacit pour un
langage de dcrire le comportement dune procdure de faon
indpendante de la nature de ses paramtres. Ainsi la procdure
qui change les valeurs de deux variables est polymorphe si lon
peut lcrire de faon indpendante du type de ses paramtres.
De faon similaire la procdure Empiler est polymorphe si elle
ne dpend pas du type de la valeur empiler.

Comme le polymorphisme est dfini par rapport la notion


de type, il ne concerne que les langages typs. On distingue
plusieurs types de polymorphisme, selon la technique employe
pour sa mise en uvre :

Le polymorphisme ad hoc consiste crire plusieurs fois le


corps de la procdure, pour chacun des types de paramtres
souhaits. Cest ce que lon appelle souvent la surcharge : on
Principes de base 27

peut dfinir Echanger (Entier, Entier) et Echanger (Disque,


Disque) de faon indpendante, de mme que Empiler (Pile,
Entier) et Empiler (Pile, Disque). Ce type de polymorphisme
est gnralement rsolu de faon statique ( la compilation). Il
utilise le systme de types pour dterminer quelle incarnation
de la procdure il faut appeler, en fonction des types effectifs
des paramtres de lappel.

Le polymorphisme dinclusion est fond sur une relation


dordre partiel entre les types : si le type B est infrieur selon
cette relation dordre au type A, alors on peut passer un objet
de type B une procdure qui attend un paramtre de type A.
Dans ce cas la dfinition dune seule procdure dfinit en
ralit une famille de procdures pour tous les types infrieurs
aux types mentionns comme paramtres. Si Entier et Disque
sont tous deux des types infrieurs Objet, on pourra dfinir
les procdure Echanger (Objet, Objet) et Empiler (Pile,
Objet).

Le polymorphisme paramtrique consiste dfinir un modle


de procdure, qui sera ensuite incarn avec diffrents types. Il
est implment par la gnricit, qui consiste utiliser des
types comme paramtres. Ainsi si lon dfinit la procdure
Echanger (<T>, <T>), on pourra lincarner avec <T> =
Entier ou <T> = Disque. On peut faire de mme pour Empiler
(Pile, <T>).

Ces trois types de polymorphisme existent dans divers


langages classiques. En Pascal le polymorphisme existe mais
nest pas accessible lutilisateur ; on ne peut donc pas le
qualifier puisque sa mise en uvre est implicite. Par exemple les
oprateurs arithmtiques sont polymorphes : laddition, la
soustraction, etc. sappliquent aux entiers, aux rels, et mme
aux ensembles. De mme, les procdures dentre-sortie read et
write sont polymorphes puisquelles sappliquent diffrents
types de paramtres.

Ada offre un polymorphisme ad hoc par la possibilit de


surcharge des noms de procdures et des oprateurs. Il offre
28 Les langages objets

galement un polymorphisme paramtrique par la possibilit de


dfinir des fonctions gnriques. En revanche le
polymorphisme dinclusion est limit car trs peu de types sont
comparables par une relation dordre.

Le polymorphisme dans les langages objets

La dfinition du polymorphisme est dpendante de la notion


de type. Pourtant, tous les langages objets ne sont pas typs.
Un langage objets typ est un langage objets dans lequel
chaque classe dfinit un type, et dans lequel on dclare
explicitement les types des objets que lon utilise. Les langages
objets typs fournissent naturellement le polymorphisme ad
hoc et le polymorphisme dinclusion. Certains langages offrent
le polymorphisme paramtrique mais il ne fait pas partie des
principes de base prsents dans ce chapitre.

Le polymorphisme ad hoc provient de la possibilit de dfinir


dans deux classes indpendantes (cest--dire nayant pas de
relation dhritage) des mthodes de mme nom. Le corps de
ces mthodes est dfini indpendamment dans chaque classe,
mais du point de vue de lutilisateur, on peut envoyer le mme
message deux objets de classes diffrentes. Ce polymorphisme
ad hoc est intrinsque aux langages objets : il ne ncessite
aucun mcanisme particulier, et dcoule simplement du fait que
chaque objet est responsable du traitement des messages quil
reoit.

La dfinition de plusieurs mthodes de mme nom dans une


mme classe ou dans des classes ayant une relation dhritage
est une forme de polymorphisme ad hoc qui nest pas implicite
dans les langages objets, bien que la plupart dentre eux
offrent cette possibilit de surcharge. De plus, la redfinition
dune mthode dans une classe drive, avec le mme nom et les
mmes paramtres que dans la classe de base, ne constitue pas
une surcharge mais une redfinition de mthode, comme nous
lavons vu dans la description de lhritage (section 2.5).
Principes de base 29

Les langages objets disposent galement naturellement dun


polymorphisme dinclusion que lon appelle aussi
polymorphisme dhritage. En effet, la hirarchie des classes
(dans le cas de lhritage simple) induit un ordre partiel : si B
hrite de A (directement ou indirectement), alors B est infrieur
A. Toute mthode de A est alors applicable un objet de classe
B : cest ainsi que lon a dfini lhritage des mthodes. Le
polymorphisme dhritage nous permet donc dappliquer la
mthode Sommet de la classe Pile un objet de la classe Tour,
puisque Tour est une sous-classe de Pile.

Le polymorphisme dhritage sapplique galement


lhritage multiple, en dfinissant une relation dordre partiel
compatible avec le graphe dhritage de la faon suivante : une
classe B est infrieure une classe A si et seulement si il existe
un chemin orient de B vers A dans le graphe dhritage. Le
graphe tant sans cycle, on ne peut avoir la fois un chemin
orient de A vers B et un chemin orient de B vers A, ce qui
assure la proprit dantisymtrie.

Le polymorphisme dhritage sapplique non seulement au


receveur des messages, mais galement au passage de paramtres
des mthodes : si une mthode prend un paramtre formel de
classe A, on peut lui passer un paramtre rel de classe B si B est
infrieur A. Ainsi la mthode Empiler prend un paramtre de
classe Entier. On peut lui passer un paramtre de classe Disque,
si Disque hrite de Entier.

Liaison statique et liaison dynamique

Le polymorphisme dhritage interdit aux langages objets


un typage exclusivement statique : un objet dclar de classe A
peut en effet contenir, lexcution, un objet dune sous-classe
de A. Les langages objets sont donc au mieux fortement typs,
ce qui a des consquences importantes pour la compilation de
ces langages. Dans un langage typage statique, le compilateur
peut dterminer quelle mthode de quelle classe est
effectivement appele lors dun envoi de message : on appelle
cette technique la liaison statique.
30 Les langages objets

Lorsque le typage statique ne peut tre ralis, on doit avoir


recours la liaison dynamique, cest--dire la dtermination
lexcution de la mthode appeler. La liaison dynamique fait
perdre un avantage important des langages compils :
lefficacit du code engendr par le compilateur. La liaison
dynamique doit aussi tre utilise dans les langages non typs,
car labsence de systme de types interdit toute dtermination a
priori de la mthode invoque par un envoi de message. Dans
les deux cas, nous verrons les techniques employes pour rendre
la liaison dynamique efficace.

Les liens troits entre polymorphisme, typage, et mode de


liaison dterminent en grande partie les compromis raliss par
les diffrents langages objets entre puissance dexpression du
langage, scurit de programmation, et performance
lexcution. De ce point de vue, il nexiste pas aujourdhui de
langage idal, et il est probable quil ne puisse en exister.

2.6 LES MTACLASSES


Nous avons dfini jusqu prsent la notion dobjet de faon
assez vague : un objet doit appartenir une classe. Certains
langages permettent de considrer une classe comme un objet ;
en temps quobjet, cette classe doit donc tre linstance dune
classe. On appelle la classe dune classe une mtaclasse (voir
figure 6).

La description que nous avons donne dune classe ressemble


effectivement celle dun objet : une classe contient la liste des
noms des champs de ses instances et le dictionnaire des
mthodes que lon peut invoquer sur les instances. La liste des
champs dune mtaclasse a donc deux lments : la liste des
noms de champs et le dictionnaire des mthodes.
Linstanciation est une opration qui est ralise par une classe ;
cest donc une mthode de la mtaclasse.

Une mtaclasse peut galement stocker dautres champs et


dautres mthodes. Ainsi, larbre dhritage tant une relation
Principes de base 31

Mtaclasse

mtaclasses

Base

Drive

classes

objets
Figure 6 - La notion de mtaclasse

entre les classes, chaque classe contient un champ qui dsigne sa


classe de base (reprsent par les flches grises paisses dans les
figures). Une mthode de la mtaclasse permet de tester si une
classe est sous-classe dune autre classe.

Plusieurs modles de mtaclasses existent. Le plus simple


consiste avoir une seule mtaclasse (appele par exemple
Mtaclasse). Le plus complet permet de dfinir arbitrairement
des mtaclasses. Cela autorise par exemple la redfinition de
linstanciation ou lajout de mthodes de classes (dfinies dans
la mtaclasse). Un modle intermdiaire, celui de Smalltalk-80,
prvoit exactement une mtaclasse par classe. Lenvironnement
de programmation se charge de crer automatiquement la
mtaclasse pour toute classe cre par le programmeur. Ce
dernier peut dfinir des mthodes de classes, qui sont stockes
dans le dictionnaire de la mtaclasse. Cette approche rend les
mtaclasses pratiquement transparentes pour le programmeur, et
offre un compromis satisfaisant dans la plupart des applications.
32 Les langages objets

Dans tous les cas, la notion de mtaclasse induit une rgression


linfini : en effet, une mtaclasse est une classe, donc un objet,
et a donc une classe ; cette classe a donc une mtaclasse, qui est
un objet, etc. Cette rgression est court-circuite par une boucle
dans larbre dinstanciation. Par exemple, la classe Mtaclasse
est sa propre mtaclasse.

Les mtaclasses ont deux applications bien diffrentes. La


premire est de permettre une dfinition mta-circulaire dun
langage et de rendre accessible ses propres structures
dexcution. On appelle cela la rification. Cette proprit existe
galement en Lisp et permet dcrire trs simplement un
interprte Lisp en Lisp. Un langage rifi permet galement de
construire facilement des moyens dintrospection pour aider
la mise au point des programmes : trace des envois de message
et des invocations de mthodes, trace des changements de valeur
des variables, etc.

La deuxime application des mtaclasses est de permettre la


construction dynamique de classes. Prenons lexemple dune
application graphique interactive dans laquelle lutilisateur peut
crer de nouveaux objets graphiques utilisables comme les
objets primitifs (cercles, rectangles, etc.). Chaque nouvel objet
graphique, lorsquil est transform en modle, donne lieu la
cration dune nouvelle classe. Cette nouvelle classe est cre
par instanciation dune mtaclasse existante. En labsence de
mtaclasses, il faudrait dune faon ou dune autre simuler ce
mcanisme, ce qui peut tre fastidieux.

Disposer de mtaclasses dans un langages objets signifie que


lon peut dynamiquement ( lexcution) dfinir de nouvelles
classes et modifier des classes existantes. Cela interdit donc tout
typage statique, et cest la raison pour laquelle les mtaclasses ne
sont disponibles que dans les langages non typs. Certains
langages typs utilisent nanmoins implicitement des
mtaclasses, en autorisant par exemple la redfinition des
mthodes dinstanciation. Il est galement possible de dfinir
des objets qui jouent le rle des mtaclasses pour la
reprsentation, lexcution, de larbre dhritage. Mais la
Principes de base 33

pleine puissance des mtaclasses reste rserve aux langages non


typs.
Chapitre 3

LANGAGES OBJETS
TYPS
Ce chapitre prsente les langages objets typs, dont Simula est
lanctre. Ce dernier tant peu utilis aujourdhui, ce sont les
langages plus rcents C++, Eiffel et Modula3 qui nous serviront
de base. La premire version de C++ a t dfinie en 1983 par
Bjarne Stroustrup aux Bell Laboratories, le mme centre de
recherches o sont ns Unix et le langage C. Eiffel est un
langage cr partir de 1985 par Bertrand Meyer de Interactive
Software Engineering, Inc. Modula3 est une nouvelle version de
Modula dveloppe depuis 1988 au Systems Research Center de
DEC sous limpulsion de Luca Cardelli et Greg Nelson.

Nous utilisons pour les exemples un pseudo-langage dont la


syntaxe, inspire en grande partie de Pascal, se veut intuitive.
Nous donnons ci-dessous la description de ce langage sous
forme de notation BNF tendue, avec les conventions suivantes :
les mots cls du langage sont en caractres gras ;
les autres terminaux sont en italique ;
36 Les langages objets

les crochets indiquent les parties optionnelles ;


la barre verticale dnote lalternative ;
les parenthses servent grouper des parties de rgles ;
+ indique la rptition au moins une fois ;
* indique la rptition zro ou plusieurs fois ;
les indicateurs de rptition peuvent tre suivis dune
virgule ou dun point-virgule qui indique le sparateur
utiliser lorsquil y a plus dun lment dans la liste ;
prog ::= ( classe | mthode )+
classe ::= id-cls = classe [id-cls +,] {
[champs champs+]
[mthodes mthodes+ ]
}
champs ::= id-champ +, : type ;
mthodes ::= procdure id-proc (param*;) ;
| fonction id-fonc (param*;) : type ;
type ::= id-cls | entier | boolen
| tableau [ const .. const ] de type
param ::= id-param +, : type
mthode ::= procdure id-cls.id-proc (param*;) bloc
| fonction id-cls.id-fonc (param*;): type bloc
bloc ::= { [decl+] instr*; }
decl ::= id-var +, : type ;
instr ::= var := expr
| [var.]id-proc (expr*,)
| tantque expr-bool faire instr
| si expr-bool alors corps [sinon instr]
| pour id-var := expr expr faire instr
| retourner [expr]
| bloc
var ::= id(.id-champ)* | var [ expr ]
id ::= id-var | id-param | id-champ
Langages objets typs 37

expr ::= var | const


| [var.]id-fonc (expr*,)
| expr ( + | - | * | / ) expr
expr-bool ::= expr ( < | > | = | ) expr
| expr-bool ( et | ou ) expr-bool
| non expr-bool

Pour complter cette description, il convient de prciser que


les commentaires sont introduits par deux tirets et se poursuivent
jusqu la fin de la ligne.

3.1 CLASSES, OBJETS, MTHODES

Dfinir une classe

La notion de classe dobjets est une extension naturelle de la


notion de type enregistrement. En effet, une classe contient la
description dune liste de champs, complte par la description
dun ensemble de mthodes.

Notre classe Pile peut scrire :


Pile = classe {
champs
pile : tableau [1..N] de entier;
sommet : entier;
mthodes
procdure Empiler (valeur: entier);
procdure Dpiler ();
fonction Sommet () : entier;
}

La dclaration dun objet correspond linstanciation :


p1 : Pile;

Linvocation des mthodes dun objet utilise loprateur


point ( . ), qui permet traditionnellement laccs un champ
38 Les langages objets

dun enregistrement. On peut donc considrer que les mthodes


se manipulent comme des champs de lobjet :

p1.Empiler (10);
p1.Empiler (15);
p1.Dpiler ();
s := p1.Sommet (); -- s vaut 10

Cette notation indique clairement quel est le receveur du


message (ici p1), la mthode invoque, et ses paramtres.
Comme lenvoi de message ncessite imprativement un
receveur, on ne peut invoquer les mthodes autrement que par
cette notation pointe :
Empiler (10)
na pas de sens car on ne connat pas le receveur du message,
sauf sil y a un receveur implicite, comme nous le verrons plus
loin.

Cette mme notation pointe permet daccder aux champs de


lobjet :
p1.pile [5];
Les rgles de visibilit empchent gnralement un tel accs aux
champs. Comme nous lavons vu au chapitre 2, les champs sont
dun accs priv tandis que les mthodes sont dun accs
public. Ceci signifie que les champs dun objet sont accessibles
seulement par cet objet, alors que les mthodes sont accessibles
par tout objet grce lenvoi de message.

Dfinir des mthodes

La dclaration dune classe contient les en-ttes des mthodes.


Nous allons dcrire leurs corps de faon spare. Pour cela,
nous utiliserons la notation classe.mthode qui permet une
qualification complte de la mthode. En effet, deux mthodes
de mme nom peuvent tre dfinies dans deux classes
diffrentes. Rappelons que cela constitue la premire forme de
polymorphisme offerte par les langages objets, le
polymorphisme ad hoc.
Langages objets typs 39

Selon les langages, la faon de dclarer les corps des mthodes


varie. La notation que nous avons choisie est inspire de C++.
Eiffel adopte une autre convention qui consiste mettre les
dclarations de mthodes dans un bloc associ la classe o
elles sont dfinies, ce qui pourrait tre transcrit de la faon
suivante dans notre pseudo-langage :
Pile = classe {
procdure Empiler (valeur : entier) {
-- corps de Empiler
}
-- etc.
}

La notation qualifie que nous avons adopte ici permet de


sparer la dclaration de la classe de la dclaration des corps des
mthodes, mais les deux mcanismes sont strictement
quivalents.

Dans notre exemple, si lon omet les tests de validit des


oprations (pile vide, pile pleine), on a les dfinitions de corps
de mthodes suivantes :
procdure Pile.Empiler (valeur: entier) {
-- attention : pas de test de dbordement
sommet := sommet + 1;
pile [sommet] := valeur;
}
procdure Pile.Dpiler () {
-- attention : pas de test de pile vide
sommet := sommet - 1;
}
fonction Pile.Sommet () : entier {
retourner pile [sommet];
}

Une mthode est toujours invoque avec un objet receveur,


qui sert de contexte son excution. Laccs aux champs de
lobjet receveur (pile et sommet dans notre exemple) se fait en
mentionnant directement leurs noms.
40 Les langages objets

Pour tre plus prcis, les entits accessibles depuis une


mthode sont :
lobjet receveur,
les champs de lobjet receveur,
les mthodes de lobjet receveur,
les paramtres de la mthode,
les variables locales de la mthode,
les objets dclars de faon globale au programme.

Les champs des objets et les paramtres tant eux-mmes des


objets, on peut invoquer leurs mthodes. Pour illustrer cela,
supposons lexistence dune classe Fichier et crivons de
nouvelles mthodes pour la classe Pile (ces mthodes doivent
tre ajoutes la dclaration de la classe Pile) :
procdure Pile.crire (sortie : Fichier) {
pour i := 1 sommet faire sortie.crire (pile [i]);
}
procdure Pile.Vider () {
tantque sommet > 0 faire Dpiler ();
}

Pile.crire invoque la mthode crire du paramtre sortie.


Elle crit sur ce fichier lensemble des lments de la pile. Nous
supposons ici que c r i r e est une mthode de la classe
Fichier.Pile.Vider invoque la mthode Dpiler sans la qualifier
par un receveur, ce qui semble contraire ce que nous avons dit
plus haut. Mais ici on est dans le contexte dun objet receveur
de classe Pile, qui devient le receveur implicite de Dpiler (voir
figure 7). Cest par un mcanisme identique que s o m m e t
reprsente le champ sommet de lobjet receveur du message.

La pseudo-variable moi

Bien que lobjet receveur soit implicite en ce qui concerne


laccs aux champs et aux mthodes, il est parfois ncessaire de
le rfrencer explicitement, par exemple pour le passer en
paramtre une autre mthode. Selon les langages, il porte le
Langages objets typs 41

1 Vider
Pile

pile 2 Vider ( ) {
sommet tant que sommet > 0 faire
Dpiler ( );
3 }

4 Dpiler ( ) {

}

Figure 7 - Accs aux champs et aux mthodes.


Les flches hachures reprsentent linvocation de mthode

nom rserv de self (Modula3, mais aussi Smalltalk),


Current (Eiffel), this (C++). Nous lappellerons moi .
Moi nest pas proprement parler un objet, mais une faon de
rfrencer le receveur de la mthode en cours dexcution. On
utilise pour cela le terme de pseudo-variable.

Lexemple suivant illustre lutilisation de moi. Les classes


Sommet et Arc permettent de reprsenter un graphe. Un sommet
est reli un ensemble darcs, et un arc relie deux sommets.

Sommet = classe {
champs
-- reprsentation des arcs adjacents
mthodes
procdure Ajouter (a : Arc);
}
Arc = classe {
champs
dpart, arrive : Sommet;
mthodes
procdure Relier (s1, s2 : Sommet);
}
42 Les langages objets

crivons le corps de la mthode Relier de la classe Arc :


procdure Arc.Relier (s1, s2 : Sommet) {
dpart := s1;
arrive := s2;
s1.Ajouter (moi);
s2.Ajouter (moi);
}

Cet exemple montre quil est indispensable de pouvoir


rfrencer explicitement le receveur du message dans le corps
de la mthode invoque : cest larc qui reoit le message Relier
qui doit tre ajout aux sommets s1 et s2.

On peut galement utiliser la pseudo-variable moi pour


qualifier les champs et les mthodes locales, mais cela napporte
rien sinon une notation plus lourde. La mthode Vider de la
classe Pile pourrait ainsi scrire comme suit :
procdure Pile.Vider () {
tantque moi.sommet > 0 faire moi.Dpiler ();
}

Les classes primitives

Nous avons utilis pour dfinir la classe Pile un champ de


type entier et un champ de type tableau, considrant ces types
comme prdfinis dans le langage. Le statut de ces types
prdfinis varie dun langage lautre. En gnral, les types
atomiques (entier, boolen, caractre) ne sont pas des classes et
on ne peut en hriter. Les types structurs comme les tableaux
sont parfois accessibles comme des classes gnriques.

On peut toujours construire une classe qui contient un champ


dun type prdfini. Malheureusement, moins de disposer de
mcanismes de conversion implicite entre types atomiques et
classes, on ne peut utiliser ces classes de faon transparente.
Par exemple, si lon dfinit la classe Entier, contenant un
champ de type entier, comme suit :
Langages objets typs 43

Entier = classe {
champs
valeur : entier;
mthodes
procdure Valeur (v : entier);
}
procdure Entier.Valeur (v : entier) {
valeur := v;
}
et si lon change le type entier par la classe Entier dans la classe
Pile, on ne peut plus crire
p1.Empiler (10);
car 10 est une valeur du type prdfini entier, et non un objet de
la classe Entier. Sans mcanisme particulier du langage, il faut
crire :
v : Entier;
v.Valeur (10);
p1.Empiler (v);

La diffrence de statut entre types atomiques et classes rsulte


dun compromis dans lefficacit de limplmentation des
langages objets typs. Cette diffrence ne pose que peu de
problmes dans la pratique, bien quelle soit peu satisfaisante
pour lesprit.

3.2 HRITAGE
Nous allons maintenant prsenter comment est mis en uvre
lun des concepts de base des langages objets : lhritage.
Nous allons pour cela prsenter les deux principales utilisations
de lhritage, la spcialisation et lenrichissement.

Spcialisation par hritage

Nous dfinissons maintenant une sous-classe de la classe Pile,


la classe Tour. Rappelons quune tour est une pile dont les
valeurs sont dcroissantes.
44 Les langages objets

Tour = classe Pile {


mthodes
procdure Initialiser (n : entier);
fonction PeutEmpiler (valeur : entier) : boolen;
procdure Empiler (valeur : entier);
}

Lhritage est mentionn dans len-tte de la dclaration


(comparer avec la dclaration de la classe Pile). La procdure
Initialiser empile n disques de tailles dcroissantes :
procdure Tour.Initialiser (n : entier) {
sommet := 0;
pour i := n 1 faire Empiler (i);
}
Initialiser invoque la mthode Empiler, qui est redfinie dans
la classe Tour. Dfinissons maintenant les corps des mthodes
PeutEmpiler et Empiler :
fonction Tour.PeutEmpiler (valeur : entier) : boolen {
si sommet = 0
alors retourner vrai;
sinon retourner valeur < Sommet ();
}
La mthode PeutEmpiler rfrence le champ sommet de sa
classe de base ainsi que la mthode Sommet dfinie galement
dans la classe de base. Elle teste si la valeur peut tre empile,
cest--dire si la tour est vide ou sinon si la valeur est plus petite
que le sommet courant de la tour. Empiler utilise PeutEmpiler
pour dcider de lempilement effectif de la valeur :
procdure Tour.Empiler (valeur : entier) {
si PeutEmpiler (valeur)
alors Pile.Empiler (valeur);
sinon erreur.crire (impossible dempiler);
}

On suppose ici lexistence dun objet global erreur, de la


classe Fichier, qui permet de communiquer des messages
lutilisateur grce sa mthode crire.
Langages objets typs 45

Pile

Empiler Tour

Empiler (valeur: entier) {



Pile. Empiler (valeur);

}

Figure 8 - Spcialisation de la mthode Empiler

Lappel de Pile.Empiler (valeur) mrite quelques explications.


La classe Tour est une spcialisation de la classe Pile, cest--
dire que lon a simplement redfini une mthode de la classe
Pile. Dans cette situation, la mthode redfinie a souvent besoin
de rfrencer la mthode de mme nom dans la classe de base.
Si lon avait crit
Empiler (valeur)
on aurait provoqu un appel rcursif, puisque lon est dans le
corps de la mthode Empiler de la classe Tour. La notation
Pile.Empiler (valeur)
permet de qualifier le nom de la mthode appele. Comme Tour
hrite de Pile, la mthode Empiler de Pile est accessible dans le
contexte courant, mais elle est cache par sa redfinition dans la
classe Tour (voir figure 8). La notation qualifie permet laccs
la mthode de la classe de base, dans le contexte de lobjet
receveur. Elle ne peut tre utilise que dans cette situation.

Une fois la classe Tour dfinie, on peut en dclarer des


instances et invoquer des mthodes :
t : Tour;
...
t.Empiler (10);
46 Les langages objets

t.Dpiler;
t.Empiler (20);
t.Empiler (5); -- impossible dempiler

Comme on la dit, les mthodes de la classe de base restent


accessibles. Dans cet exemple, t.Dpiler invoque Pile.Dpiler.

Enrichissement par hritage

Nous allons maintenant dfinir une classe drive de la classe


Tour en ajoutant la possibilit de reprsenter graphiquement la
tour. Pour cela nous supposons lexistence des classes Fentre et
Rectangle, avec les dfinitions partielles suivantes :

Fentre = classe {
mthodes
procdure Effacer ();
}

Rectangle = classe {
mthodes
procdure Centre (posX, posY : entier);
procdure Taille (largeur, hauteur : entier);
procdure Dessiner (f : Fentre);
}

TourG est une sous-classe de Tour dfinie comme suit :

TourG = classe Tour {


champs
f : Fentre;
x, y : entier;
mthodes
procdure Placer (posX, posY : entier);
procdure Dessiner ();
procdure Empiler (valeur: entier);
procdure Dpiler ();
}
Langages objets typs 47

Il sagit ici dun enrichissement : trois nouveaux champs


indiquent la fentre de lcran dans laquelle sera affiche la
tour, et la position de la tour dans cette fentre. Chaque tage de
la tour sera reprsent par un rectangle de taille proportionnelle
la valeur entire qui le reprsente dans la tour. Deux nouvelles
mthodes permettent daffecter une position la tour et de
dessiner la tour. Enfin, les mthodes Empiler et Dpiler sont
redfinies afin dassurer que la tour est redessine chaque
modification. Le corps des mthodes est dcrit ci-dessous.

Placer affecte la position de la tour et la redessine.


procdure TourG.Placer (posX, posY : entier) {
x := posX;
y := posY;
Dessiner ();
}

Dessiner commence par effacer la fentre, puis redessine la


tour tage par tage. Dessiner est similaire dans son principe la
mthode crire dfinie auparavant dans la classe Pile.
procdure TourG.Dessiner () {
rect : Rectangle;
f.Effacer ();
pour i := 1 sommet faire {
rect.Centre (x, y - i);
rect.Taille (pile [i], 1);
rect.Dessiner (f);
}
}

Empiler et Dpiler invoquent la mthode de mme nom dans


la classe de base Tour et redessinent la tour. On pourrait bien sr
optimiser laffichage, mais ce nest pas lobjet de lexemple.
procdure TourG.Empiler (valeur: entier) {
Tour.Empiler (valeur);
Dessiner ();
}
48 Les langages objets

procdure TourG.Dpiler () {
Tour.Dpiler ();
Dessiner ();
}

Il est noter que Tour.Dpiler na pas t dfinie. En fait la


classe Tour hrite Dpiler de la classe Pile, donc Tour.Dpiler est
identique Pile.Dpiler. Nanmoins, il serait imprudent
dutiliser Pile.Dpiler directement car on peut tre amen
redfinir Dpiler dans Tour.

3.3 HRITAGE MULTIPLE


Lhritage multiple permet dutiliser plusieurs classes de base.
La classe TourG, par exemple, reprsente une tour qui sait
safficher dans une fentre. En changeant lgrement de point
de vue, on peut considrer que la classe TourG est la fois une
tour et une fentre. On a alors un hritage multiple de Tour et
de Fentre (figure 9). Voyons la dfinition de la classe TourGM
ainsi obtenue :

TourGM = classe Tour, Fentre {


champs
x, y : entier;
mthodes
procdure Placer (posX, posY : entier);
procdure Dessiner ();
procdure Empiler (valeur: entier);
procdure Dpiler ();
}

Lhritage multiple est mentionn en faisant apparatre la liste


des classes de base dans len-tte de la dclaration. Le champ f
napparat plus : il est remplac par lhritage de Fentre.

La seule mthode qui change par rapport la classe TourG est


la mthode Dessiner :
Langages objets typs 49

Pile

Tour Fentre

Tour GM

Figure 9 - Hritage multiple de la classe TourGM

procdure TourGM.Dessiner () {
rect : Rectangle;
Effacer ();
pour i := 1 sommet faire {
rect.Centre (x, y - i);
rect.Taille (pile [i], 1);
rect.Dessiner (moi);
}
}

On constate que linvocation de la mthode Effacer nest plus


qualifie par le champ f. En effet, cette mthode est maintenant
hrite de la classe Fentre. Par ailleurs, linvocation de la
mthode Dessiner prend comme argument la pseudo-variable
moi. En effet, TourGM hrite maintenant de Fentre, donc une
T o u r G M est une fentre : on utilise ici le polymorphisme
dhritage sur le paramtre de la mthode Dessiner.

Bien que les diffrences entre les implmentations de TourG et


TourGM soient minimes, leffet de lhritage multiple est plus
important quil ny parat. En effet, alors que TourG nhrite
50 Les langages objets

que des mthodes de Tour, TourGM hrite de celles de Tour et


de Fentre. Il est donc tout fait possible dcrire :
tgm : TourGM;

tgm.Placer (100, 100);
tgm.Empiler (20);
tgm.Empiler (10);
tgm.Effacer ();

Linvocation dEffacer est correcte puisque Effacer est hrite


de Fentre. Pour un objet de la classe TourG, cet envoi de
message aurait t illicite. On voit donc que le choix
dimplmenter une tour graphique par la classe TourG ou la
classe T o u r G M dpend du contexte dutilisation dans
lapplication. Lhritage, comme lhritage multiple, ne doit pas
tre utilis comme une facilit dimplmentation, mais comme
une faon de spcifier des liens privilgis entre classes.

Lhritage multiple cre cependant une ambigut : supposons


que la classe Fentre dfinisse une mthode crire, qui imprime
son tat. La classe Tour de son ct hrite une mthode crire
de la classe Pile. Que se passe-t-il si lon crit :
tgm.crire (fich);

Il y a un conflit car la classe TourGM hrite deux fois de la


mthode crire. Les langages rsolvent ce problme de
diffrentes manires :
lordre de lhritage multiple dtermine une priorit entre
les classes ; dans notre cas TourGM hrite dabord de Tour,
puis de Fentre, donc Tour.crire masque Fentre.crire.
Le rsultat est donc dimprimer la tour, cest--dire la pile.
il faut qualifier linvocation de la mthode, par exemple
tgm.Fentre.crire (fich). Cela suppose donc que
lutilisateur connaisse le graphe dhritage, ce qui ne
favorise pas lide dencapsulation et dabstraction. Cest le
mcanisme choisi par Modula3 et C++.
il faut renommer, lors de lhritage, les mthodes qui
engendrent des conflits. On peut ainsi hriter de Tour, et de
Langages objets typs 51

Fentre en renommant la mthode crire hrite de fentre


en crireF. tgm.crire(fich) imprime donc la tour, alors que
tgm.crireF(fich) imprime la fentre. Cest le mcanisme
impos par Eiffel, et disponible en C++.
il faut dfinir une mthode crire dans la classe TourGM,
qui lvera le conflit en masquant les deux mthodes crire.
La dernire mthode est toujours ralisable. Dans notre
exemple, on pourrait dfinir cette mthode de la faon suivante :
procdure TourGM.crire (sortie : Fichier) {
Tour.crire (sortie);
Fentre.crire (sortie);
sortie.crire (x);
sortie.crire (y);
}

Cette mthode crit la partie Tour, la partie Fentre et les


champs propres de T o u r G M . Les invocations qualifies
Tour.crire et Fentre.crire lvent lambigut en mme temps
quelles vitent lappel rcursif de TourGM.crire.

Lorsque des champs de plusieurs classes de base portent le


mme nom, les mmes problmes de conflits daccs se posent.
Ils sont rsolus par un accs qualifi (en C++) ou par
renommage (en Eiffel).

Nous avons voqu au chapitre prcdent dautres problmes


concernant lhritage multiple, et notamment lhritage rpt :
que se passe-t-il si une classe hrite, directement ou
indirectement, plusieurs fois de la mme classe ? Faut-il
dupliquer les champs de cette classe ou doivent-ils apparatre
une seule fois ?

En C++, la notion de classe de base virtuelle permet de ne voir


quune fois une classe de base qui est accessible par plusieurs
chemins dhritage. En Eiffel, le contrle est plus fin car chaque
champ dune classe de base hrite plusieurs fois peut tre
dupliqu ou partag, selon que le champ est renomm ou non.
52 Les langages objets

3.4 LIAISON DYNAMIQUE


Tel que nous lavons prsent, lhritage des mthodes dans
un langage objets typ permet de dterminer de faon statique
les invocations de mthodes : pour un objet o de la classe A,
lappel
o.m (paramtres)
est rsolu en recherchant dans la classe A une mthode de nom
m. Si elle nest pas trouve, la recherche se poursuit dans la
classe de base de A, et ainsi de suite jusqu trouver la mthode
ou atteindre la racine de larbre dhritage. Si la mthode est
trouve, linvocation de mthode est correcte, sinon elle est
errone.

Le compilateur peut profiter de cette recherche, destine


vrifier la validit du programme, pour engendrer le code qui
appelle directement la mthode trouve. Cela vite une
recherche similaire lexcution et rend donc le programme
plus efficace. Cela sappelle la liaison statique.

Malheureusement, le polymorphisme dhritage rend cette


optimisation invalide, comme le montre lexemple suivant :
t : Tour ;
tg : TourG ;
...
t := tg ;
t.Empiler (10) ; -- que se passe-t-il ?

Laffectation de la tour graphique tg la tour simple t est


correcte en vertu du polymorphisme dhritage : une tour
graphique est un cas particulier de tour, donc un objet de type
tour peut rfrencer une tour graphique. En utilisant la liaison
statique, le compilateur rsout linvocation dEmpiler par
lappel de Tour.Empiler, car t est dclar de type Tour. Mais t
contient en ralit, lors de lexcution, un objet de classe TourG,
et linvocation de Tour.Empiler est invalide : il aurait fallu
invoquer TourG.Empiler.
Langages objets typs 53

Dans cet exemple, le typage statique ne nous permet pas de


savoir que t contient en ralit un objet dune sous-classe de
Tour et la liaison statique brise la smantique du polymorphisme
dhritage.

Les mthodes virtuelles

Ce problme avait t not ds Simula, et rsolu en


introduisant la notion de mthode virtuelle : en dclarant
Empiler virtuelle, on indique dutiliser une liaison dynamique et
non plus une liaison statique : le contrle de type a toujours lieu
la compilation, mais la dtermination de la mthode appeler
a lieu lexcution, en fonction du type effectif de lobjet. On
comprend aisment que la liaison dynamique est plus chre
lexcution que la liaison statique, mais quelle est indispensable
si lon veut garder la smantique du polymorphisme dhritage.

Lexemple suivant montre une autre situation dans laquelle les


mthodes virtuelles sont indispensables :
tg : TourG ;
tg.Initialiser (4);
On initialise une tour graphique avec quatre disques. Nous
allons voir que l encore, il faut que Empiler ait t dclare
virtuelle. La procdure Initialiser est hrite de Tour. Voici
comment nous lavons dfinie :
procdure Tour.Initialiser (n : entier) {
pour i := n 1 faire Empiler (i);
}

Si Empiler nest pas dclare virtuelle, son invocation est


rsolue par liaison statique par lappel de Tour.Empiler, puisque
le receveur est considr de classe Tour. Lorsque lon invoque
tg.Initialiser(4), le receveur sera en ralit de classe TourG, et
cest la mauvaise version dEmpiler qui sera invoque (voir
figure 10). En dclarant Empiler virtuelle, ce problme disparat.
En loccurrence, cest TourG.Empiler qui sera invoque,
provoquant le dessin de la tour au fur et mesure de son
initialisation.
54 Les langages objets

Tour

Empiler (v) {}

Statique
Initialiser (n) { 3'
pour i := n 1
Empiler (i)
}
2

Dynamique
Initialiser (4)
1
3
TourG
tg
Empiler (v) {}

Figure 10 - Liaison statique contre liaison dynamique

Lutilisation extensive du polymorphisme dans les langages


objets pourrait laisser penser que toutes les mthodes doivent
tre virtuelles. Cest la solution choisie dans Eiffel et Modula3,
qui assurent au programmeur que tout se passe comme si la
liaison tait toujours dynamique.

Par contre, C++ et Simula obligent dclarer explicitement les


mthodes virtuelles comme telles. Cela offre au programmeur la
possibilit de choisir entre la scurit de la liaison dynamique et
lefficacit de la liaison statique, ses risques et prils. En
pratique, on se rend compte quun nombre limit de mthodes
ont effectivement besoin dtre virtuelles, mais quil est difficile
de dterminer lesquelles, surtout lorsque les classes sont
destines tre rutilises.

Limplmentation de la liaison dynamique

Limplmentation usuelle de la liaison dynamique consiste


attribuer chaque mthode virtuelle un indice unique pour la
Langages objets typs 55

Pile

Empiler Code de Pile.Empiler


une Pile Dpiler Code de Pile.Dpiler

Tour
une autre Pile
Empiler Code de Tour.Empiler
Depiler

Tables virtuelles
une Tour

Figure 11 - Implmentation de la liaison dynamique

hirarchie de classes laquelle elle appartient. Lors de


lexcution, chaque classe est reprsente par une table, qui
contient pour un indice donn ladresse de la mthode
correspondante de cette classe. Chaque objet dune classe
contenant des mthodes virtuelles contient ladresse de cette
table (figure 11). Linvocation dune mthode exige
simplement une indirection dans cette table. Le cot de
limplmentation est donc le suivant :
une table, dite table virtuelle, par classe ;
un pointeur vers la table virtuelle par objet ;
une indirection par invocation de mthode virtuelle.

On peut considrer ce cot comme acceptable, surtout si on le


compare au cot dinvocation des mthodes dans les langages
non typs (dcrit la fin de la section 4.3 du chapitre 4). On
peut aussi considrer quil est inutile de supporter ce cot
systmatiquement, et cest la raison pour laquelle Simula et C++
donnent le choix (et la responsabilit) au programmeur de
56 Les langages objets

dclarer virtuelles les mthodes quil juge utile. Modula3, au


contraire, tire parti de la table virtuelle ncessaire chaque objet
pour autoriser un objet redfinir des mthodes : il suffit de lui
crer une table virtuelle propre. On quitte alors le modle strict
des langages de classes, puisque ce nest plus la classe qui
dtient le comportement de toutes ses instances.

3.5 RGLES DE VISIBILIT


La dclaration explicite des types dans un langage assure la
dtection derreurs ds la compilation, et permet donc au
programmeur de se protger contre lui-mme. Un autre aspect
de cette protection concerne les rgles de visibilit, cest--dire
les mcanismes dencapsulation qui permettent de limiter
laccs des donnes et mthodes. Le rle principal de
lencapsulation est de masquer les dtails dimplmentation
dune classe afin dviter que des clients extrieurs puissent la
modifier impunment. On peut alors modifier a posteriori les
parties caches sans effet perceptible pour les clients.

Nous avons considr jusqu prsent que les rgles de


visibilit taient les suivantes :
Les champs dune classe sont visibles seulement dans le
corps des mthodes de cette classe et de ses classes drives.
Les mthodes dune classe sont visibles de lextrieur par
tout client.
Lunit de lencapsulation : classe ou objet

La premire rgle ci-dessus est ambigu : soit une classe A et


une mthode m de cette classe ; on peut comprendre la rgle de
deux faons :
dans le corps de m, on a accs aux champs de nimporte
quel objet de classe A (en particulier le receveur de m) ;
dans le corps de m , on na accs quaux champs de son
receveur. Par exemple, si m a un paramtre de classe A, m
na pas accs aux champs de ce paramtre.
Langages objets typs 57

Cette deuxime interprtation est plus restrictive. Elle


correspond un domaine de visibilit qui est lobjet : un objet
nest connu que des mthodes de sa classe, une mthode ne
connat que les champs de son receveur. La premire
interprtation correspond un domaine de visibilit qui est la
classe tout entire : une classe connat ses instances, donc toute
mthode de cette classe connat toute instance de cette classe.
Cette interprtation est celle utilise dans les langages de la
famille Simula. linverse, les langages de la famille Smalltalk
adoptent gnralement la premire interprtation, et considrent
donc lobjet comme lunit de lencapsulation.

Une fois dfinie cette notion de domaine de visibilit, il reste


montrer les diffrents mcanismes offerts par les langages.
Modula3, C++ et Eiffel prsentent de ce point de vue des
approches diffrentes.

Modula3 : visible ou cach

Par dfaut, tous les champs et mthodes dune classe Modula3


sont visibles de nimporte quel client. Nanmoins, un
mcanisme permet de crer un type opaque identique une
classe donne, dont on ne rend visible que les mthodes
souhaites. Ce mcanisme, assez lourd, oblige crer au moins
deux types par classe : un type ouvert contenant les champs et
mthodes, et un type ferm, utilis par les clients, ne prsentant
que les mthodes utiles.

Dun autre ct, cette technique permet de dfinir plusieurs


interfaces une classe donne en dfinissant plusieurs types
limitant laccs cette classe de diffrentes manires. Ainsi on
peut imaginer quune classe drive souhaite un accs plus large
sa classe de base quune classe quelconque.

C++ : priv, protg ou public

En C++, les mcanismes de visibilit sappliquent


indiffremment aux champs et aux mthodes, que nous
appellerons collectivement des membres dans cette section,
58 Les langages objets

conformment la terminologie C++. Le type de visibilit offert


par C++ est intermdiaire entre ceux de Modula3 et Eiffel. Un
membre dune classe peut tre dclar avec lun des trois
niveaux de visibilit1 suivants : priv, protg, public.
Un membre priv nest visible que depuis les mthodes de
la classe dans laquelle il est dfini. Aucune classe extrieure
ny a accs, pas mme une classe drive.
Un membre public est au contraire accessible tout client.
Enfin, un membre p r o t g nest accessible quaux
mthodes de la classe et de ses classes drives. Cela entrine
le fait quune classe drive est un client privilgi de sa
classe de base.

Ces niveaux de visibilit sont transmis par hritage : un


membre public dune classe A est public dans toute classe
drive de A. De mme, un membre protg dans A est protg
dans toute classe drive de A. En revanche, un membre priv
nest pas visible dans une classe hrite.

C++ offre trois mcanismes complmentaires en ce qui


concerne la visibilit :
lhritage priv permet de construire une classe B drive
dune classe A sans que ce lien dhritage ne soit visible de
lextrieur : les membres hrits de A sont privs dans B, et
il ny a pas de polymorphisme dinclusion entre B et A.
une classe peut rexporter un membre hrit avec un niveau
de visibilit diffrent. Par exemple, la mthode protge m
dune classe A peut tre rendue publique dans une classe B
drive de A. Dans le cas de lhritage priv, on peut ainsi
rendre visibles certains membres de la classe de base.
une classe peut avoir des classes amies et des mthodes
amies : une classe B amie de A ou une mthode f amie de A
a accs tous les membres de la classe A. Cela permet

1 En C++, on parle d'accessibilit plutt que de visibilit. Bien que la


diffrence soit significative, nous n'entrerons pas dans les dtails ici.
Langages objets typs 59

douvrir une classe des clients privilgis, sans toutefois


autoriser laccs une classe sans son consentement. En
effet, cest la classe A qui doit dclarer que B et f sont amies.

Eiffel : exportation explicite

Le mcanisme le plus raffin pour ce qui concerne les rgles


de visibilit est celui dEiffel : chaque classe dcrit la liste des
membres quelle exporte. Chaque membre ainsi export peut
tre qualifi par une liste de classes clientes. Par dfaut, un
membre export est visible par nimporte quel client. Si lon
qualifie le membre avec une liste de classes, alors ce membre
nest visible que par ces classes et leurs classes drives.

Le contrle de la visibilit des membres hrits est ralis par


le mme mcanisme. On peut retransmettre les membres hrits
avec la visibilit dclare dans la classe de base, ou bien changer
leur visibilit.

Des progrs faire

Diverses raisons dordre syntaxique peuvent faire prfrer tel


ou tel mcanisme de visibilit. Dans tous les cas, il nest pas
facile de matriser la combinaison entre la visibilit, lhritage et
le polymorphisme.

La diversit syntaxique cache un rel problme smantique :


on ne matrise pas aujourdhui les notions de visibilit de faon
satisfaisante, et cest la raison pour laquelle il nexiste pas de
mcanisme simple qui rponde des besoins par ailleurs mal
dfinis : la visibilit doit tre compatible avec lhritage, mais
des classes sans relation dhritage doivent pouvoir se connatre
de faon privilgie, comme les amis de C++. Ds lors, un
mcanisme global est ncessaire mais pas suffisant. Des travaux
sur la notion de vue, assez proche du mcanisme de Modula3,
sont prometteurs : ils permettent de dfinir plusieurs vues dune
classe donne, cest--dire plusieurs interfaces. Un client choisit
alors la vue qui lintresse. Cet aspect des langages objets nest
60 Les langages objets

donc pas fig, et lon peut sattendre de nouvelles solutions


court terme.

3.6 MCANISMES SPCIFIQUES

Initialisation des objets

Lun des problmes classiques dans les langages qui


manipulent des variables (et, dans notre cas, des objets) est celui
de linitialisation. Ainsi, en Pascal, une variable non initialise ne
sera pas repre par le compilateur et pourra provoquer un
comportement alatoire du programme. Mme lorsque les
variables non initialises sont repres par le compilateur, le
programmeur doit les initialiser explicitement, ce qui alourdit le
programme. La notion dobjet offre un terrain favorable pour
assurer linitialisation des objets. En effet, on peut imaginer
quune mthode particulire prenne en charge automati-
quement linitialisation de tout nouvel objet. C++ et Eiffel
offrent de tels mcanismes.

Une classe Eiffel peut dclarer une mthode spciale, de nom


prdfini Create, qui assure linitialisation des objets de cette
classe. Le programmeur doit invoquer explicitement cette
mthode, qui a un statut particulier. Ainsi, linstruction o.Create
invoque en ralit les mthodes Create de la classe de o et de
chacune de ses classes de base. Cela assure que tous les
composants de o sont initialiss correctement. Il sensuit que la
mthode Create ne shrite pas ; le compilateur engendre au
contraire une mthode C r e a t e pour les classes qui nen
dfinissent pas. Cette mthode initialise chacun des champs
une valeur par dfaut dpendant de son type.

En C++, une classe peut dclarer des constructeurs, mthodes


spciales qui portent le nom de la classe elle-mme. Divers
constructeurs, avec des listes de paramtres diffrentes,
permettent de dfinir plusieurs moyens dinitialisation. Un
constructeur sans paramtre est un constructeur par dfaut.
Lappel du constructeur est ralis automatiquement, par le
Langages objets typs 61

compilateur, chaque dclaration dobjet. Comme en Eiffel, le


constructeur dune classe drive appelle automatiquement celui
de sa classe de base. Par contre, linverse dEiffel, lappel du
constructeur est implicite, ce qui vite les oublis malencontreux.
De faon symtrique linitialisation, C++ permet la dfinition
de mthodes spcifiques pour la destruction des objets : ces
destructeurs sont, comme les constructeurs, invoqus automati-
quement lorsquun objet devient inaccessible. Ainsi un objet
dclar comme variable locale dune mthode voit son
destructeur appel lorsque la mthode termine son excution.

La destruction assure des objets est aussi importante que leur


initialisation. Par exemple, si lon considre un objet
reprsentant un fichier, le destructeur peut assurer la fermeture
du fichier lorsque celui nest plus accessible. Le plus souvent,
les destructeurs sont utiliss pour dtruire des structures
dynamiques contenues dans les objets. Ainsi, une classe Liste,
contenant une liste chane dobjets allous dynamiquement,
peut assurer la destruction de ses lments dans son destructeur.

Voici comment lon pourrait dfinir et utiliser un constructeur


et un destructeur pour la classe Tour. Nous avons pour cela
tendu la syntaxe de notre langage par lajout des mots cls
constructeur et destructeur.
Tour = classe Pile {

mthodes
constructeur Tour (taille : entier);
destructeur Tour ();

}
constructeur Tour (taille : entier) {
Initialiser (taille);
}
destructeur Tour () {
tantque sommet > 0 faire Dpiler ();
}
62 Les langages objets

{ -- exemple dutilisation
t : Tour (10); -- constructeur Tour (entier)

} -- appel du destructeur de t

Gnricit

Tout au long de ce chapitre, nous avons utilis la classe Pile


pour reprsenter une pile dentiers. Si lon voulait grer une
pile dautres objets, il faudrait dfinir une nouvelle classe,
probablement trs proche dans sa dfinition et son impl-
mentation de la classe Pile. La gnricit, qui met en uvre le
polymorphisme paramtrique, est un mcanisme attrayant pour
dfinir des types gnraux. Par exemple, toute classe contenant
une collection dobjets est un bon candidat pour une classe
gnrique : tableau, liste, arbre, etc. En effet de telles classes
conteneurs dpendent peu de la classe des objets contenus.

La gnricit nous permet de dfinir une classe gnrique


GPile, paramtre par le type de ses lments :
GPile = classe (T : classe) {
champs
pile : tableau [1..N] de T;
sommet : entier;
mthodes
procdure Empiler (val : T);
procdure Dpiler ();
fonction Sommet () : T;
}
Pile = classe GPile (entier); -- instanciation
p : Pile;
p.Empiler (10);
On ne peut utiliser la classe G P i l e telle quelle : il faut
linstancier en lui donnant le type de ses lments. En revanche,
on peut driver GPile ; la classe drive est elle aussi gnrique.

La gnricit et lhritage sont deux mcanismes qui


permettent de dfinir des familles potentiellement infinies de
Langages objets typs 63

classes. Aucun nest rductible lautre, et un langage objets


qui offre la gnricit est strictement plus puissant quun
langage qui ne loffre pas. Eiffel permet la dfinition de classes
gnriques. La gnricit est galement dfinie pour C++, mais
elle nest pas implmente dans les compilateurs actuels.

Gestion dynamique des objets

Nous avons introduit la notion dobjet dans ce chapitre en


gnralisant la notion denregistrement prsente dans des
langages tels que Pascal. En Pascal comme dans dautres
langages, on peut dclarer des objets qui ont une dure de vie
dlimite par leur porte (variables locales), mais on peut aussi
grer des variables dynamiques par lintermdiaire des
pointeurs. Lutilisation de variables dynamiques laisse au
programmeur la charge de dtruire les variables inutilises,
moins que le module dexcution du langage noffre un
ramasse-miettes qui dtruise automatiquement les variables
devenues inaccessibles.

En C++, les objets sont implments par des enregistrements,


et le programmeur peut utiliser des objets automatiques ou des
pointeurs vers des objets dynamiques. Dans ce cas, lallocation
dynamique et la libration de la mmoire pour les objets
devenus inutiles ou inaccessibles est sa charge. Les notions de
constructeurs et de destructeurs aident cette gestion sans la
rendre totalement transparente. linverse, Modula3 et Eiffel
assurent eux-mmes la gestion dynamique de la mmoire. Un
objet est en ralit un pointeur vers lenregistrement de ses
champs. Cette implmentation facilite le travail du
programmeur, qui na pas se soucier de la destruction des
objets : un algorithme de ramasse-miettes sen occupe pour lui
lexcution. Le choix dimplmenter les objets par des
pointeurs, et non par des enregistrements comme en C++, offre
lavantage de la simplicit. En revanche, laccs tout champ
dun objet ncessite une indirection lors de lexcution, ce qui
peut tre coteux. De plus, les algorithmes de ramasse-miettes
aujourdhui disponibles sont gnralement peu efficaces, et
cotent cher en temps et en espace mmoire lors de lexcution.
64 Les langages objets

Bien entendu, ce problme nest pas propre aux langages


objets. Nanmoins, on pourrait esprer que le choix du langage
nimplique pas le choix de la gestion des objets lexcution.
Cest le cas dans Modula3, o lon peut indiquer pour chaque
classe si lon souhaite une gestion automatique par ramasse-
miettes, ou bien une gestion la charge du programmeur. C++
permet galement au programmeur de redfinir la gestion des
objets dynamiques au niveau de chaque classe. On peut ainsi
utiliser les proprits spcifiques dune classe pour grer la
mmoire plus efficacement quavec un ramasse-miettes gnral.

3.7 CONCLUSION
La richesse des langages objets typs est encore loin dtre
puise. Les langages actuels souffrent encore du lourd hritage
des langages structurs. De nombreux travaux de recherche
concernent la smantique des systmes de types mis en uvre
dans ces langages, et dcouvrent la complexit des problmes
mis en jeu ds lors que lon veut combiner hritage multiple,
gnricit, surcharge, etc. Les langages actuels ont dj fait la
preuve de leurs qualits : scurit pour le programmeur, facilit
de maintenance, rutilisation des classes, efficacit du code
excutable. Ils sont de plus en plus facilement adopts dans les
entreprises pour le dveloppement de logiciels complexes :
systmes dexploitation, environnements de programmation,
interfaces graphiques, simulation, etc.
Chapitre 4

SMALLTALK
ET SES DRIVS
Nous allons prsenter dans ce chapitre le langage Smalltalk et
les langages qui en sont drivs. Ils prsentent la caractristique
commune dtre des langages non typs et interprts ou semi-
compils.

La premire version de Smalltalk date de 1972 et fut inspire


par les concepts de Simula et les ides dAlan Kay, au
laboratoire PARC de Xerox. Aprs une dizaine dannes
defforts et plusieurs versions intermdiaires, notamment
Smalltalk-72 et Smalltalk-76, Smalltalk-80 reprsente la version
la plus rpandue du langage et de la bibliothque de classes qui
laccompagne. Smalltalk-80 inclut galement un systme
dexploitation et un environnement de programmation
graphique. Xerox a aussi cr des machines spcialises pour
Smalltalk : le Star et le Dorado. Aujourdhui, Smalltalk est
disponible sur stations de travail Unix, sur Apple Macintosh, et
sur compatibles IBM PC.
66 Les langages objets

La syntaxe employe dans ce chapitre pour prsenter les


exemples est proche de celle de Smalltalk. Les commentaires
sont introduits par deux tirets et se poursuivent jusqu la fin de
la ligne. Toute instruction est un envoi de message, qui a lune
des formes suivantes :

receveur msg1
receveur msg2 argument
receveur cl1: arg1 cl2: arg2 cln: argn

La premire forme est un envoi de message unaire (message


sans argument), par exemple :
3 factorielle -- calculer 3!
Tableau Nouveau -- crer un nouveau tableau

La deuxime forme est un envoi de message binaire (message


avec un argument). Les expressions arithmtiques et
relationnelles sont exprimes avec des messages binaires :
3+4 -- receveur = 3, msg = +, argument = 4
a<b -- receveur = a, msg = <, argument = b

Enfin la troisime forme est utilise pour des messages n-aires


( un ou plusieurs arguments) et est appele message mots
cls. Chaque mot cl se termine par le symbole : et
correspond un argument :
tab en: 3 mettre: a

Ici le receveur est tab, le message est en:mettre: et les


arguments sont 3 et a. Le nom du message est la concatnation
des mots cls (y compris les deux-points). Les noms de message
peuvent tre prfixes les uns des autres. Dans ce cas, on prend la
plus longue srie de mots cls. Les parenthses permettent de
lever les ambiguts ou de forcer lordre dvaluation. titre
dexemple, nous utiliserons les messages en: et en:mettre:, pour
laccs aux lments de tableau :

tab en: 3 -- tab [3]


tab en: 4 mettre: a -- tab [4] := a
tab en: (tab en: 5) mettre: a -- tab [tab [5]] := a
Smalltalk et ses drivs 67

La premire expression retourne llment du tableau tab


lindice 3. La deuxime affecte a llment dindice 4. La
dernire expression affecte a tab [tab [5]]. Dans la ralit, en:
et en:mettre: ne sont pas ddis ni rservs laccs aux
tableaux, ceux-ci ntant pas un type prdfini de Smalltalk.

Les deux autres symboles utiliss dans notre langage sont le


symbole daffectation et le symbole de retour de valeur
. Nous aurons galement besoin de blocs qui seront dcrits
dans la section suivante.

Bien que Smalltalk permette de dfinir des classes et des


mthodes par envoi de messages, nous utiliserons une forme
plus lisible qui sapparente celle offerte par lenvironnement
graphique de programmation Smalltalk. La dclaration dune
classe aura la forme suivante :
classe idClasse
superclasse idClasse
champs id1 id2 idn
mthodes
suite de dclarations de mthodes

Lajout de mthodes dans une classe existante aura une forme


identique, en omettant les lignes superclasse et mthodes.

Une dclaration de mthode se prsente comme suit :


cl1: arg1 cl2: arg2 cln: argn
| idvar1 idvar2 idvarn |
corps de la mthode

La premire ligne est le profil de la mthode. Ici, il sagit


dune mthode mots cls. La deuxime ligne est optionnelle et
permet de dclarer des variables locales. Enfin le corps de la
mthode est une suite dexpressions Smalltalk, spares par des
points.
68 Les langages objets

4.1 TOUT EST OBJET


Les concepts de base de Smalltalk peuvent se dcrire en quatre
axiomes :

1. Toute entit est un objet.


2. Tout objet est linstance dune classe.
3. Toute classe est sous-classe dune autre classe.
4. Tout objet est activ la rception dun message.

Laxiome 2 dfinit la notion dinstanciation. Laxiome 3


dfinit la notion dhritage. Bien distinguer ces deux types de
liens (lien dinstanciation est-instance-de et lien dhritage est-
sous-classe-de) est fondamental la comprhension de
Smalltalk. Il dcoule des axiomes 1 et 2 que toute classe est une
entit du systme, donc un objet. En tant quobjet, toute classe
est donc linstance dune classe, que lon appelle sa mtaclasse.
Cette notion de mtaclasse est fondamentale dans Smalltalk, et
nous y reviendrons plus loin en dtail.

Les seules entits prdfinies dans le langage sont :


les nombres entiers, dfinis dans la classe Entier ;
la classe Objet qui est la seule ne pas respecter le troisime
axiome (Objet nest la sous-classe daucune classe) ;
la classe Bloc dtaille ci-dessous ;
la mtaclasse Classe.

La seule structure de contrle est lenvoi de message aux


objets. En particulier, le langage ne contient aucune structure de
contrle telles que conditionnelle, boucles, etc. Celles-ci sont
dfinies grce la notion de bloc. Un bloc est une instance de la
classe prdfinie Bloc. Un bloc contient une liste optionnelle de
paramtres et un ensemble dexpressions Smalltalk excutables,
spares par des points. Lvaluation dun bloc est obtenue en
lui envoyant le message unaire valeur. Les blocs sont nots entre
crochets :
Smalltalk et ses drivs 69

incr [ n n + 1 ].
incr valeur. -- ajoute 1 n

On peut comparer les blocs des procdures anonymes que


lon peut excuter par lenvoi du message valeur, ou des
lambda-expressions de Lisp. Les blocs peuvent avoir des
paramtres. Dans ce cas, le bloc commence par la liste des noms
des paramtres, prfixs dun deux-points, et cette liste est
spare du corps du bloc par une barre verticale. Le message
valeur: prend comme argument la valeur du paramtre rel.
Nous utiliserons seulement des blocs avec un paramtre :

ajouter [ :x | n n + x ]. -- paramtre = x
ajouter valeur: 10. -- ajouter 10 n

Le langage est donc rduit au strict minimum. De ce point de


vue, on peut comparer Smalltalk au langage Lisp. Comme Lisp,
Smalltalk est fourni avec un environnement qui vite au
programmeur de tout reconstruire dans chaque programme. Cet
environnement est un ensemble de classes dintrt gnral
telles que boolens, tableaux, chanes de caractres, etc. Il
contient galement les classes de lenvironnement de
programmation Smalltalk, qui permettent notamment de
construire des applications graphiques interactives.

4.2 CLASSES, INSTANCES, MESSAGES


Le deuxime axiome indique que tout objet est linstance
dune classe. Prcisons ce que sont les objets et les classes : un
objet contient un tat, stock dans un ensemble de champs
(appels en Smalltalk variables dinstance). Ces champs sont
strictement privs et accessibles seulement par lobjet. Un objet
ne peut tre manipul qu travers les messages quon lui
envoie. Chaque objet rpond un message en activant une
mthode (axiome 4). Les mthodes ne sont pas stockes dans
lobjet lui-mme, mais dans sa classe. Le lien dinstanciation qui
unit lobjet sa classe est donc crucial : il lui permet de
retrouver la mthode activer la rception dun message.
70 Les langages objets

Nouveau

Pile Pile

Figure 12 - Instanciation dun objet Smalltalk

Les mthodes sont stockes dans la classe avec leurs corps,


dans le dictionnaire des mthodes. Une classe contient
galement la liste des noms des champs de ses instances. Cela lui
permet de crer de nouvelles instances : une classe est un objet
gnrateur. La cration dun objet, ou instanciation, est ralise
en envoyant le message Nouveau une classe. La classe, en tant
quobjet, rpond au message Nouveau en crant un nouvel objet
(figure 12). Linstanciation, si elle est une opration primitive
du langage, est nanmoins ralise par le seul moyen de
contrle quest lenvoi de message.

Pour rsumer les points prcdents :


un objet contient un ensemble de champs ;
une classe contient la description des champs de ses
instances et le dictionnaire des mthodes que peuvent
excuter ses instances ;
un objet est cr par lenvoi du message Nouveau sa
classe.

La correspondance entre un message reu par un objet et la


mthode activer se fait simplement sur le nom du message :
lobjet recherche dans le dictionnaire des mthodes de sa classe
une mthode portant le mme nom que le message. Si une telle
mthode existe, elle est excute dans le contexte de lobjet
receveur. Le corps de la mthode peut donc accder aux
champs de lobjet qui, rappelons-le, lui sont privs.
Smalltalk et ses drivs 71

La rception dun message qui na pas de mthode


correspondante dans le dictionnaire des mthodes de sa classe
provoque une erreur. Lerreur se manifeste par lenvoi dun
message NeComprendsPas: lobjet qui a reu le message
incompris, avec pour argument le nom du message incompris.
Lobjet a donc lopportunit de rcuprer lerreur : il suffit que
sa classe dtienne une mthode de nom NeComprendsPas:. Si ce
nest pas le cas, une erreur fatale dexcution est dclenche.

Le mcanisme de rponse un message est dynamique et non


typ : seule compte la classe de lobjet receveur, qui dtermine
le dictionnaire dans lequel la mthode est recherche. Un mme
message peut donc donner lieu lexcution de mthodes
diffrentes sil est reu par des objets de classes diffrentes. La
classe des arguments nintervient pas : si lon veut imposer
quun argument dun message appartienne une classe donne,
la mthode correspondante doit faire les tests ncessaires.
Comme les classes sont des objets, on peut tester si la classe dun
objet est gale une classe donne.

Laspect dynamique de lenvoi de message apparat lorsque


lon modifie au cours de lexcution le dictionnaire des
mthodes dune classe. Un message qui tait prcdemment
incompris peut tre dfini en cours dexcution. Comme la
dfinition de mthode se fait par envoi de message, une
mthode peut dfinir dautres mthodes, de la mme faon
quune fonction Lisp peut dfinir dautres fonctions.

Crer une classe

Il est temps de passer un exemple, et de prsenter


limplmentation en Smalltalk de la classe Pile. Pour cette
classe, nous utilisons la classe Tableau de lenvironnement
Smalltalk. Nous utilisons deux messages de cette classe :
le message en: qui permet daccder un lment de
tableau,
le message en:mettre: qui permet de modifier la valeur dun
lment de tableau.
72 Les langages objets

classe Pile
superclasse Objet
champs pile sommet
mthodes
Initialiser
pile Tableau Nouveau.
sommet 0.
Empiler: unObjet
sommet sommet + 1.
pile en: sommet mettre: unObjet.
Dpiler
sommet sommet - 1.
Sommet
pile en: sommet.

La classe Pile hrite de la classe Objet, qui est une classe


prdfinie en Smalltalk. Une pile a deux champs : un tableau
qui reprsente la pile, et lindice du sommet de la pile dans le
tableau. On peut rfrencer dans un corps de mthode les
arguments du message, ainsi que les noms des champs de la
classe. Ces noms de champs font rfrence aux champs de
lobjet receveur du message.

Nous avons dfini quatre mthodes dans la classe Pile :


Initialiser initialise les champs de la pile ; le champ pile
reoit un objet de la classe Tableau, et le champ sommet est
initialis 0.
Empiler est un message qui prend un objet en argument
(lobjet empiler). Notre pile est htrogne : aucun
contrle nest fait sur la classe des objets empils. On peut
donc empiler des objets de classes diffrentes.
Dpiler enlve le sommet de pile.
Sommet retourne le sommet courant.

Notre pile nest pas trs sre : il ny a pas de contrle dans


Dpiler ni dans Sommet pour sassurer que la pile nest pas
vide. Nous pourrons ajouter ces tests lorsque lon aura dcrit la
faon de raliser des conditionnelles.
Smalltalk et ses drivs 73

Pour utiliser la classe Pile, il suffit den crer une instance et


de lui envoyer des messages :
mapile Pile Nouveau. -- instanciation
mapile Initialiser.
mapile Empiler: 10.
mapile Empiler: 15.
mapile Dpiler.
s mapile Sommet. -- s contient 10
o UneClasse Nouveau.
mapile Empiler: o.
mapile Empiler: mapile. -- !!
La dernire instruction, pour surprenante quelle paraisse, est
tout fait correcte, puisque lon peut empiler nimporte quel
objet.

4.3 HRITAGE
Laxiome 3 indique que toute classe est sous-classe dune
autre classe. Cet axiome dtermine larbre dhritage qui lie les
classes entre elles. Nous avons vu quune classe prdfinie,
Objet, faisait exception cet axiome. Objet est la racine de
larbre dhritage, cest--dire que, directement ou
indirectement, toute classe est une sous-classe de Objet.

Lhritage permet de dfinir une classe partir dune autre,


en conservant les proprits de la classe dont on hrite. Une
sous-classe est un enrichissement dune classe existante : on
peut ajouter de nouveaux champs et de nouvelles mthodes. On
peut galement modifier le comportement de la classe de base
en redfinissant des mthodes.

Lhritage modifie la recherche de mthode que nous avons


dcrite dans la section prcdente : lorsquun message est reu
par un objet, celui recherche dabord dans le dictionnaire des
mthodes de sa classe. Sil ne trouve pas de mthode, il poursuit
la recherche dans sa classe de base, et ainsi de suite jusqu
trouver une mthode ou bien atteindre la racine de larbre
dhritage, savoir la classe Objet.
74 Les langages objets

Objet

NeComprendsPas 6
(Coucou)
3
(NeComprendsPas)
Pile (Coucou)

Dpiler 5
2
b

NeComprendsPas: Coucou

4
Dpiler a
Coucou 1

Figure 13 - Invocation de mthode.


Les flches hachures reprsentent la recherche de mthode.
Lenvoi de Dpiler russit, mais lenvoi de Coucou choue

Dans le cas o le message na pas de mthode associe, le


message NeComprendsPas: est envoy au receveur du message,
avec comme argument le nom du message incompris. La
recherche dune mthode de nom NeComprendsPas: suit le
mme mcanisme : recherche dans la classe de lobjet, puis ses
superclasses successives. La classe prdfinie Objet dfinit la
mthode NeComprendsPas, de telle sorte que lon est assur de
ne pas chouer cette fois-ci (figure 13). Cette technique de
traitement des messages incompris permet toute classe de
redfinir la mthode NeComprendsPas: et de raliser une
rcupration derreur, sans introduire de mcanisme
supplmentaire dans le langage tel que la notion dexception.
Smalltalk et ses drivs 75

Dfinir une sous-classe

Voyons comment dfinir une classe HPile, sous-classe de Pile,


dans laquelle on force les lments appartenir une mme
classe. Il sagit dajouter un champ qui stocke la classe des
objets que lon empile, ainsi quune mthode qui permet
daffecter ce champ. Enfin, il faut redfinir la mthode Empiler
afin de raliser le contrle de la classe de lobjet empil.

Pour dcrire cette classe, il nous faut introduire la


conditionnelle, qui a la forme suivante :
bool siVrai: [ blocSiVrai ] siFaux: [ blocSiFaux ]

Il sagit de lenvoi du message siVrai:siFaux: un objet de la


classe Boolen. Les arguments du message sont deux blocs,
correspondant aux actions effectuer selon que lobjet receveur
est lobjet vrai ou lobjet faux. Nous verrons plus loin comment
sont dfinies la classe Boolen et les structures de contrle telles
que celle-ci.

La dfinition de la classe HPile est la suivante :


classe HPile
superclasse Pile
champs classe
mthodes
Classe: uneClasse
classe uneClasse.
self Initialiser.
Empiler: unObjet
unObjet Classe = classe
siVrai: [ super Empiler: unObjet ]
siFaux: [ Empiler: erreur de classe crire ]

La mthode Classe: permet de dfinir la classe des objets que


lon met dans la pile. Elle affecte le champ classe et excute self
Initialiser. La mthode Empiler: est redfinie de manire tester
la classe de lobjet empil. Pour cela, on utilise la mthode
Classe, dfinie dans la classe Objet, qui retourne la classe de son
receveur. Le receveur du message siVrai:siFaux: est le rsultat
76 Les langages objets

de lexpression unObjet Classe = classe. Cette expression se


dcompose en un envoi du message unaire Classe unObjet. Le
rsultat est compar au champ classe par le message binaire =.
Le bloc excuter si lexpression est vraie, cest--dire si lobjet
est de la classe attendue, est super Empiler. Si lexpression est
fausse, un message derreur est mis en envoyant le message
crire une chane de caractres. Il nous reste dcrire self
(utilis dans Classe:) et super (utilis dans Empiler:).

Self et Super

Nous avons vu que le corps dune mthode sexcute dans le


contexte de lobjet receveur du message. lintrieur du corps
dune mthode, on a directement accs aux champs de lobjet
receveur. En revanche, si lon veut envoyer un message au
receveur lui-mme, il faut un moyen de le nommer. On utilise
alors la pseudo-variable self, qui dsigne le receveur de la
mthode en cours dexcution. Ainsi, dans la mthode Classe:
ci-dessus, le receveur du message senvoie lui-mme (self) le
message Initialiser.

Lorsque lon veut redfinir une mthode dans une sous-classe,


on a en gnral besoin dutiliser la mthode de mme nom
dfinie dans la classe de base. Pour cela, on utilise une autre
pseudo-variable, super, qui dnote lobjet receveur en le
considrant comme une instance de sa classe de base (ou
superclasse, do le nom de super). Ceci est illustr par la
mthode Empiler:. Il sagit de tester une condition (lobjet est-il
de la bonne classe ?), et si celle-ci est satisfaite, dempiler
effectivement llment. Pour cela, on envoie le message
Empiler: super. Si on lenvoyait self, on aurait un appel
rcursif, ce qui nest pas leffet souhait. Lenvoi s u p e r
signifie que la recherche dune mthode pour le message
Empiler commence la superclasse du receveur, et non pas sa
classe comme cest le cas normalement (figure 14).

Dans la pratique, on utilise super seulement dans le corps


dune mthode redfinie, comme nous venons de le faire. Cest
en effet la seule situation dans laquelle il est justifi dinvoquer
Smalltalk et ses drivs 77

Empiler
Pile
1
Empiler: v [ ]

Hpile

2 Empiler: v [ 3

super Empiler: v
]

Figure 14 - Les pseudo-variables self et super

limplmentation de la mme mthode dans la classe de base.


Utiliser super dans un autre contexte revient transgresser la
classe de lobjet receveur.

Limplmentation de lenvoi de message

Lhritage et la possibilit de modifier dynamiquement les


dictionnaires des mthodes impliquent que, pour chaque envoi
de message, on effectue lexcution une recherche dans la
chane des superclasses de la mthode correspondant au
message. Il en rsulte que lenvoi de message est trs coteux.

Comme la hirarchie dhritage et les dictionnaires de


mthodes changent peu par rapport au nombre de messages
envoys, une augmentation des performances importante est
obtenue dans la plupart des implmentations en utilisant un
cache. Les entres du cache sont constitues de couples <nom
de classe, slecteur de message>. Pour chaque entre, le cache
contient le rsultat de la recherche du message dans la classe et
ses superclasses. Lors dun envoi de message, on cherche dans
78 Les langages objets

le cache une entre correspondant la classe de lobjet receveur


du message et au slecteur du message. Si lentre nest pas
dans le cache on effectue la recherche dans les dictionnaires, et
on entre le rsultat dans le cache. Avec cette technique, on
obtient facilement des taux de prsence dans le cache de plus de
98%, et une augmentation importante des performances.

Le cache doit tre invalid, cest--dire vid, chaque fois que


larbre dhritage ou un dictionnaire de mthode change.
Chaque ajout de classe ou de mthode cote donc cher. Aussi,
diverses techniques permettent de ne pas invalider tout le cache
afin de rduire le cot de ces modifications.

4.4 LES STRUCTURES DE CONTRLE


Un aspect original de Smalltalk est de ne pas contenir de
structures de contrle prdfinies. Celles-ci sont dfinies par des
classes et des mthodes, laide de la classe prdfinie des blocs,
comme nous allons lillustrer ici.

Les boolens et la conditionnelle

Revenons tout dabord sur la conditionnelle, que nous avons


dj utilise. Le receveur du message siVrai:siFaux: est un
boolen ; selon sa valeur, cest lun des deux blocs arguments
du message qui est excut. Pour produire cela, on dfinit trois
classes et deux objets :
la classe Boolen, qui na aucune instance ;
la classe Vrai, sous-classe de Boolen, qui a une seule
instance : lobjet vrai ;
la classe Faux, sous-classe de Boolen, qui a une seule
instance : lobjet faux.

Le receveur de siVrai:siFaux: ne peut tre que lobjet vrai ou


lobjet faux. Ainsi, lvaluation de 3 < 4 retourne lobjet vrai,
alors que 1 = 0 retourne lobjet faux. Il suffit donc de dfinir la
mthode siVrai:siFaux: dans chacune des classes Vrai et Faux :
Smalltalk et ses drivs 79

classe Vrai
superclasse Boolen
champs
mthodes
siVrai: blocVrai siFaux: blocFaux
blocVrai valeur.

classe Faux
superclasse Boolen
champs
mthodes
siVrai: blocVrai siFaux: blocFaux
blocFaux valeur.

Comme on le voit, si lobjet v r a i reoit un message


siVrai:siFaux:, il retourne la valeur du premier argument ; si
cest lobjet faux qui reoit le message, il retourne la valeur du
deuxime argument. Lhritage nous a permis de reproduire un
comportement conditionnel. Cette technique sapplique
dautres messages, tels que les oprateurs logiques :

classe Vrai classe Faux


mthodes mthodes
non non
faux. vrai.
ou: unBool ou: unBool
vrai. unBool.
et: unBool et: unBool
unBool. faux.

La dfinition des mthodes non, ou: et et: dans les deux


classes Vrai et Faux permet dimplmenter facilement les tables
de vrit de ces oprateurs. La figure 15 illustre lvaluation
dune expression boolenne qui utilise ces oprateurs.

Jusquici la classe Boolen ne nous a pas servi : en fait Vrai et


Faux auraient trs bien pu hriter directement de Objet. Nous
allons maintenant utiliser la classe Boolen pour factoriser des
mthodes entre les classes Vrai et Faux :
80 Les langages objets

Vrai Faux

non: ou: unBool


fau
faux x unBool fa
ux

2 3 5 6

vrai faux

1 4
vrai non ou: faux faux

Figure 15 - valuation de lexpression (vrai non) ou: faux

classe Boolen
superclasse Objet
champs
mthodes
siVrai: unBloc
self siVrai: unBloc siFaux: [ ].
siFaux: unBloc
self siVrai: [ ] siFaux: unBloc.
xor: unBool
(self ou: unBool)
et: ((self et: unBool) non).

On a dfini dans la classe Boolen deux conditionnelles


siVrai: et siFaux:, qui correspondent la conditionnelle
siVrai:siFaux: lorsque lon omet lun des blocs. Il est inutile de
dfinir ces conditionnelles dans les deux classes Vrai et Faux,
comme le montre la figure 16. De faon similaire, le ou exclusif
(xor) est dfini partir des oprateurs lmentaires et:, ou: et
non, selon lexpression : a xor b = (a ou b) et non (a et b).
Smalltalk et ses drivs 81

Vrai Faux

non: ou: unBool


fau
faux x unBool fa
ux

2 3 5 6

vrai faux

1 4
vrai non ou: faux faux

Figure 16 - valuation des conditionnelles

Les blocs et les boucles

En ce qui concerne les structures de boucles, ce nest plus


dans la classe Boolen que vont se faire les dfinitions, mais
dans la classe des blocs. Dcrivons tout dabord la boucle tant-
que :

classe Bloc
mthodes
tantQueVrai: corps
(self valeur) siVrai: [ corps valeur.
self tantQueVrai: corps ].

Le message tantQueVrai: sutilise de la faon suivante :


[ x < 10 ] tantQueVrai: [ s s + x ; x x -1 ]

Le receveur est un bloc, car celui-ci doit tre valu chaque


tour de boucle, comme le montre limplmentation de la
mthode tantQueVrai: : le bloc receveur svalue ; sil est vrai,
le corps de la boucle est valu, et litration a lieu grce
82 Les langages objets

lenvoi (rcursif) du message tantQueVrai: au bloc receveur.


Comme toujours avec Smalltalk, il ny a aucun contrle de type
et rien nempche dcrire :
[ 10 ] tantQueVrai: [ ].
coucou tantQueVrai: [ ].

Selon la valeur retourne par lvaluation du bloc receveur,


une erreur aura lieu ou lexcution pourra continuer. Dans le
premier cas, lvaluation du bloc receveur retourne la valeur 10,
de la classe Entier, qui ne sait rpondre siVrai:. Dans le
deuxime cas, le receveur est une chane de caractres, qui ne
sait rpondre au message valeur. Mais si lon dfinissait ces
mthodes, lexcution pourrait se poursuivre.

Le dernier type de structure de contrle que nous allons


examiner est litration. Il sagit dexcuter un corps de boucle
(un bloc) un certain nombre de fois. Pour reproduire
lquivalent de la boucle itrative de Pascal, il faut dfinir une
classe Intervalle, qui contient deux entiers reprsentant les
bornes infrieure et suprieure de lintervalle. La mthode
rpter:, envoye un intervalle, ralise litration :

classe Intervalle
superclasse Objet
champs inf sup
mthodes
Inf: i Sup: s
inf i. sup s.
rpter: corps
|i|
i inf.
[ i < sup ] tantQueVrai:
[ corps valeur: i.
i i + 1 ].

La mthode Inf:Sup: permet dinitialiser les bornes de


lintervalle. La mthode rpter: introduit une variable locale i.
Cette variable sert de compteur de boucle, et lon utilise le
message tantQueVrai: des blocs pour raliser litration.
Smalltalk et ses drivs 83

Le message rpter: sutilise comme suit :


bornes Intervalle Nouveau.
bornes Inf: 10 Sup: 20.
s 0.
bornes rpter [ :x | s s + x ].
s crire. -- s = 165

Pour faciliter lcriture de litration, nous allons ajouter un


message dans la classe prdfinie Entier :
classe Entier
mthodes
: val (Intervalle Nouveau) Inf: self Sup: val.

Ce message permet de crer un intervalle en envoyant un


entier le message : avec un entier en argument. Le receveur est
la borne infrieure de lintervalle, largument la borne
suprieure. Lexemple prcdent scrit alors :
s 0.
(10 : 20) rpter [ :x | s s + x ].
s crire.

Lexpression 10 : 20 retourne un intervalle auquel on envoie


le message ditration rpter.

Cette technique ditration sapplique de nombreuses


classes. Ainsi, Smalltalk fournit un grand nombre de classes
conteneurs pour le stockage dobjets (tableaux, listes, ensembles,
dictionnaires, etc.). La plupart de ces classes dfinissent une
mthode qui permet litration de leurs lments.

Nous pouvons appliquer cela notre classe Pile, en lui


ajoutant une mthode rpter: qui value un bloc pour les
lments successifs de la pile :
classe Pile
mthodes
rpter: unBloc
(1 : sommet) rpter:
[ :i | unBloc valeur: (pile en: i) ].
84 Les langages objets

On utilise un intervalle cr par le message : reprsentant


lensemble des indices valides de la pile. Lintervalle est
numr par la mthode rpter:. Pour chaque lment de
lintervalle, on value le bloc argument avec comme paramtre
llment de pile.

Pour imprimer le contenu dune pile, il suffit dcrire :


pile Pile Nouveau.
pile Initialiser.
-- empiler des lments
pile rpter: [ :e | e crire ].

Nous avons dfini la mthode rpter: dans la classe Pile


laide de la mthode rpter: de la classe Intervalle, cest--dire
que lon utilise le polymorphisme ad hoc, intrinsque aux
langages objets. Ceci nous permet par exemple de dfinir dans
la classe Objet elle-mme une mthode qui imprime le contenu
dun objet de la faon suivante :
classe Objet
mthodes
crireContenu
self rpter: [ :e | e crire ].

Tout objet qui sait rpondre rpter: pourra excuter


crireContenu :
(10 : 20) crireContenu.
pile Pile Nouveau.
pile Initialiser.
-- empiler des lments
pile crireContenu.

Dans cette section, nous avons dfini litration (message


rpter:) de la classe Pile en fonction de litration des
intervalles. Celle-ci est dfinie en fonction de la rptition des
blocs (tantQueVrai:), elle-mme dfinie rcursivement laide
de la conditionnelle siVrai:. Enfin cette conditionnelle est
dfinie en fonction de la conditionnelle gnrale siVrai:siFaux:,
dfinie dans les deux classes Vrai et Faux.
Smalltalk et ses drivs 85

Cet exemple illustre la souplesse et la puissance de Smalltalk,


grce lutilisation extensive de la liaison dynamique : il suffit
de rajouter des mthodes une classe (comme rpter: dans la
classe Pile), pour que les instances de cette classe soient dotes
de nouvelles capacits (comme crireContenu). Ceci fait de
Smalltalk un environnement idal pour le maquettage et le
prototypage dapplications. En revanche, labsence de typage,
donc dassurance a priori quun programme ne dclenchera pas
dexcution de messages indfinis, est souvent un obstacle la
ralisation dapplications finales.

4.5 MTACLASSES
Nous avons vu ds la prsentation des axiomes de base de
Smalltalk que toute classe est un objet, et appartient donc une
classe, appele mtaclasse. Cette caractristique est la base de
nombreuses possibilits intressantes dans Smalltalk.

En premier lieu, la notion de mtaclasse permet de raliser


linstanciation par un envoi de message : lenvoi du message
Nouveau une classe retourne une instance de cette classe. Le
message tant envoy une classe, cest dans sa mtaclasse
quest cherche la mthode correspondante (figure 17).

La mtaclasse ne sert pas seulement linstanciation. En effet,


une classe contient la dfinition de ses instances, cest--dire la
liste des noms de champs et le dictionnaire des mthodes. On
peut donc interroger la classe pour savoir si une mthode
particulire est dfinie, pour modifier le dictionnaire des
mthodes, et pour dfinir de nouvelles sous-classes. Une
mtaclasse dfinit pour cela les mthodes Connat:, Superclasse
et DriveDe:. Le message Connat: permet de savoir si une
classe sait rpondre au message dont le nom est pass en
argument. Le message Superclasse retourne la classe de base de
la classe receveur, et enfin le message DriveDe: permet de tester
si la classe receveur est une classe drive de la classe dont le
nom est pass en paramtre. Voici quelques exemples
dutilisation de ces messages :
86 Les langages objets

Classe Classe

Nouveau

2 Pile Pile

1 Nouveau

Figure 17 - Cration dun objet : utilisation de la mtaclasse

Pile Connat: Empiler:. -- vrai


Pile Connat: SiVrai:. -- faux
Vrai Superclasse. -- Boolen
Vrai DriveDe: Pile. -- faux
HPile DriveDe: Objet. -- vrai

Le corps des mthodes correspondant ces messages se trouve


dans le dictionnaire des mthodes de la mtaclasse de leur
receveur, comme le prouvent les exemples suivants :
Pile Connat: Nouveau. -- faux
(Pile Classe) Connat: Nouveau. -- vrai

Dans le cas de Smalltalk, plusieurs modles de mtaclasses ont


t expriments. Le plus simple comprenait une seule
mtaclasse dans le systme, nomme Classe. Dans les versions
suivantes de Smalltalk, cela sest avr tre une limitation, car on
ne pouvait diffrencier les mtaclasses de classes distinctes. Le
modle de Smalltalk-80 dfinit une mtaclasse par classe, et la
hirarchie dhritage des mtaclasses suit celle des classes.
Chaque classe est lunique instance de sa mtaclasse. Pour
Smalltalk et ses drivs 87

MtaClasse Objet

Classe

ClasseTour
Pile

ClassePile
Tour

Figure 18 - Le modle des mtaclasses de Smalltalk-80

lutilisateur, les mtaclasses sont transparentes car elles sont


cres automatiquement par la mthode de dfinition de classe.

Par convention, nous appellerons ClasseX la mtaclasse de la


classe X. La mtaclasse de Objet est donc ClasseObjet, celle de
Pile est ClassePile. Comme Pile hrite de Objet, ClassePile
hrite de ClasseObjet. Les mtaclasses hritent de Classe, qui
elle-mme hrite de Objet.

Le mcanisme des mtaclasses induit une rgression linfini.


En effet, une mtaclasse est aussi un objet, qui a donc une classe,
une mtaclasse, etc. Comme dans le cas de la hirarchie
dhritage, cette rgression est artificiellement interrompue par
un bouclage dans le chanage des mtaclasses : dans Smalltalk-
80, toutes les mtaclasses hritent de la classe Classe, et sont des
instances de MtaClasse, selon le schma de la figure 18.
88 Les langages objets

Du point de vue du programmeur, cet artifice est de peu


dimportance. Il assure au langage la mta-circularit, cest--
dire la capacit se dcrire lui-mme. Grce aux mtaclasses on
peut crire un interprte Smalltalk en Smalltalk.

Lintrt des mtaclasses pour le programmeur

Pour le programmeur, les mtaclasses permettent dune part


de dfinir des mthodes de classe, et dautre part de partager des
champs entre toutes les instances dune classe.

Les mthodes de classe sont des mthodes dfinies dans une


mtaclasse, et qui sont utilises lorsque lon envoie des messages
une classe. Lutilisation la plus rpandue des mthodes de
classe est la redfinition de la mthode dinstanciation Nouveau,
et la dfinition dautres mthodes dinstanciation prenant des
paramtres. On peut rapprocher cela des constructeurs de
certains langages objets typs (voir chapitre 3, section 3.6).

Reprenons le cas de la classe Pile. Nous avons dfini dans


cette classe la mthode Initialiser qui permet dinstancier et
dinitialiser les champs de la pile. Lors de lutilisation de la
classe Pile, il faut sassurer dinitialiser chaque pile aprs lavoir
instancie avec Nouveau :
pile Pile Nouveau.
pile Initialiser.

Si lon oublie linitialisation, la pile ne pourra pas fonctionner


comme prvu. Il serait plus sr dassurer linitialisation lors de
linstanciation. Il suffit pour cela de redfinir la mthode
Nouveau, de la faon suivante :
classe ClassePile
mthodes
Nouveau
| pile |
pile super Nouveau.
pile Initialiser.
pile.
Smalltalk et ses drivs 89

ClassePile
Pile
Nouveau
Initialiser
3 6

ClasseTour
Tour 5
Nouveau 2

Nouveau 1

4
Initialiser

Figure 19 - Hritage des mthodes de classes

Cette mthode est dfinie dans la mtaclasse de Pile, puisque


cest la classe Pile qui recevra le message Nouveau. Cette
mthode commence par instancier la pile en senvoyant le
message Nouveau. Nouveau va donc tre envoy la mtaclasse
ClassePile, considre comme instance de sa classe de base
ClasseObjet. Cela va invoquer la mthode Nouveau dfinie pour
tous les objets dans la mtaclasse Classe. La pile rsultante est
ensuite initialise : le message Initialiser est envoy la pile,
cest donc la mthode Initialiser que nous avons crite dans la
classe Pile qui va tre invoque. Enfin la pile initialise est
retourne. On aurait pu condenser le corps de la mthode en :
super Nouveau Initialiser.

Dans le corps de cette mthode, on na pas accs aux champs


de lobjet pile. Il est donc impossible dinitialiser ces champs
autrement que par lenvoi dun message la pile.

Dautre part, comme on a redfini la mthode Nouveau, toute


classe qui hrite de Pile utilisera galement cette mthode
redfinie, grce au paralllisme entre lhritage des classes et
90 Les langages objets

celui des mtaclasses. Par exemple, linstanciation de la classe


HPile assurera son initialisation, comme le montre la figure 19.

Les mtaclasses permettent galement de dfinir des mthodes


dinstanciation avec paramtres. Dans lexemple suivant, on
dfinit une mthode dinstanciation qui permet de donner la
taille de la pile sa cration :

classe Pile
mthodes
Initialiser: taille
pile Tableau Nouveau: taille.
sommet 0.

classe ClassePile
mthodes
Nouveau: taille
super Nouveau Initialiser: taille.

On ajoute la classe Pile une mthode Initialiser: qui prend la


taille de la pile ; cet argument est transmis la mthode
Nouveau: de la classe Tableau. On dfinit ensuite la mthode
Nouveau: dans la mtaclasse de Pile, qui instancie une pile et
linitialise avec la taille donne. Cette mthode Nouveau: est un
message binaire quil ne faut pas confondre avec le message
unaire Nouveau que nous avons utilis jusqu prsent. Une fois
dfinie cette mthode de classe, lutilisation dune pile devient :
pile Pile Nouveau: 100.
pile Empiler: 10.

Selon le mme mcanisme, on pourrait dfinir une mthode


dinstanciation pour la classe HPile qui prenne en paramtre la
classe des objets de la pile homogne.

Variables de classe

Lautre utilisation des mtaclasses concerne la possibilit de


dfinir de nouveaux champs dans une classe. De fait, ces
champs sont accessibles par toutes les instances dune classe
Smalltalk et ses drivs 91

(toute instance connat sa classe) et jouent le rle de variables


globales dune classe.

Pour illustrer cela, nous allons crer une classe dobjets dont
les instances ont un numro unique. La mtaclasse a un champ
qui est incrment chaque instanciation :

classe Dmo
superclasse Objet
champs numro
mthodes
Initialiser: n
numro n.
Numro
numro.

classe ClasseDmo
champs nb
mthodes
Nouveau
nb nb + 1.
(super Nouveau) Initialiser: nb.

La classe Dmo contient un champ stockant le numro unique


de linstance, une mthode dinitialisation, et une mthode qui
retourne le numro de lobjet. On ajoute la mtaclasse de
Dmo une variable de classe nb, et on redfinit la mthode
dinstanciation Nouveau. Cette mthode incrmente la variable
de classe nb, puis instancie lobjet et linitialise avec la valeur de
nb.

4.6 LES DRIVS DE SMALLTALK


Smalltalk, influenc par Lisp, est lorigine dune famille de
langages objets implments au-dessus de Lisp. Il savre en
effet que limplmentation des mcanismes des langages
objets en Lisp est relativement aise, et fournit un terrain
dexprimentation de nouveaux concepts.
92 Les langages objets

Parmi les plus anciennes extensions de Lisp avec des objets, on


trouve Flavors, qui a servi implmenter le systme
dexploitation des machines Symbolics au dbut des annes 80.
Plus rcemment, CLOS (Common Lisp Object System) a repris
et tendu le modle des Flavors dans le but de dfinir une
norme de Lisp objets. Ceyx et ObjVLisp reprsentent lcole
franaise : Ceyx a t dvelopp vers 1985 au-dessus de
Le_Lisp par Jean-Marie Hullot, et ObjVLisp, un peu plus ancien,
est lobjet des travaux de Pierre Cointe partir de VLisp, un
dialecte de Lisp dvelopp par Patrick Greussay lUniversit
de Vincennes.

Tous ces langages procdent de principes similaires : il sagit


dextensions de Lisp, cest--dire que le programmeur utilise
des fonctions Lisp pour crire ses programmes2 . Leffet nest
pas toujours heureux car le style fonctionnel est assez
radicalement diffrent du style de la programmation par objets.

Ces langages fournissent en gnral trois fonctions de base : la


cration dune nouvelle classe, la cration dune instance, et
lenvoi dun message un objet. La fonction de cration dune
classe permet de spcifier son hritage (simple ou multiple), ses
variables dinstances, ses mthodes, et ventuellement sa
mtaclasse. En gnral, le systme est capable de gnrer
automatiquement des fonctions daccs aux variables
dinstance. En effet, celles-ci sont stockes dans une liste
associe latome qui reprsente lobjet, et elles ne peuvent tre
accdes autrement que par une fonction. Cet artifice est
nanmoins pratiquement transparent pour lutilisateur, comme
le montre lexemple ci-dessous :

(def-classe Pile (Objet) -- classe, superclasse


(pile sommet)) -- variables dinstance

2 La suite de cette section ncessite en consquence quelques notions


lmentaires de Lisp. Nous esprons cependant ne pas trop ennuyer le lecteur
peu familier avec Lisp en limitant les exemples.
Smalltalk et ses drivs 93

(def-mthode
(Empiler Pile) (objet) -- mthode, classe, arguments
(setq sommet (+ sommet 1))
(envoi mettre pile sommet objet))

Dans cet exemple, dont la syntaxe est inspire de Flavors, def-


classe dfinit une nouvelle classe, et def-mthode une nouvelle
mthode dans une classe existante. Le corps de la mthode
Empiler est constitu de deux expressions : laffectation (setq en
Lisp) du champ sommet et lenvoi du message mettre au champ
pile. Ce message est suppos stocker lobjet pass en second
argument lindice pass en premier argument. Lenvoi de
message est une fonction qui sinvoque de la manire suivante :
(envoi message receveur arg1 arg2 argn)

On peut retrouver une syntaxe plus proche de celle de


Smalltalk en transformant chaque objet en une fonction, ce que
font certains langages. Lenvoi de message scrit alors :
(receveur message arg1 arg2 argn)

La cration dune pile et lempilement dun lment se font


de la manire suivante :
(setq mapile (instancier Pile))
(envoi Initialiser mapile)
(envoi Empiler mapile 10)

La fonction instancier ralise linstanciation dune classe. La


mthode Initialiser est dfinie comme suit :
(def-mthode
(Initialiser Pile) () -- mthode, classe, arguments
(setq pile (instancier Tableau))
(setq sommet 0))

Lintrt dutiliser Lisp comme langage de base est de


disposer dun environnement dj important qui simplifie
limplmentation des mcanismes dobjets. La souplesse de
Lisp permet galement dexprimenter facilement de nouvelles
fonctionnalits et des extensions au modle gnral des objets.
94 Les langages objets

Les dmons des Flavors

Ainsi les Flavors fournissent des mcanismes sophistiqus


pour lhritage multiple. On a vu que lhritage multiple
provoquait des conflits de noms lorsque plusieurs classes de
base dfinissent une mthode de mme nom. Les Flavors
permettent de dterminer, pour chaque classe, lordre de
parcours du graphe des superclasses pour dterminer la bonne
mthode invoquer. Il est galement possible de combiner
lensemble des mthodes de mme nom hrites, cest--dire de
les invoquer lune aprs lautre. Enfin, on peut dfinir des
dmons, qui sont des mthodes spciales associes aux mthodes
ordinaires. Lorsque la mthode ordinaire est invoque, tous les
dmons qui lui sont associs dans la classe ou dans ses
superclasses sont galement automatiquement invoqus, selon
un ordre que le programmeur peut contrler. Par exemple, pour
tracer les invocations du message Empiler, il suffit dajouter le
dmon suivant :
(def-dmon
(Empiler Pile) (objet) -- mthode, classe, arguments
(print "on Empile " objet))

Mme si lon redfinit Empiler dans une sous-classe de Pile, le


dmon sera appel. Dans la pratique, la combinaison de
mthodes et les dmons sont des mcanismes extrmement
puissants, qui sont par l mme difficile matriser : lenvoi
dun message un objet peut dclencher une quantit deffets
dont lorigine risque dtre difficile identifier. De la mme
faon, une modification locale du systme, comme lajout ou le
retrait dun dmon, peut provoquer des effets rapidement
incontrlables. Les programmeurs Lisp sont coutumiers de ce
genre de phnomnes, et trouveront dans ces langages un terrain
dexprimentation encore plus vaste.

Les mtaclasses dObjVLisp

Nous terminerons cette revue des drivs de Lisp par


ObjVLisp et son modle de mtaclasses. En effet, ce langage
Smalltalk et ses drivs 95

Classe Objet

ClassePile Pile

unePile

Tour
uneTour

Figure 20 - Le modle de mtaclasses de ObjVLisp

offre ce que lon peut considrer comme le modle la fois le


plus simple et le plus ouvert de mtaclasses (figure 20).

Les classes Classe et Objet sont les deux classes primitives du


systme. Objet est une instance de Classe, et Classe est une sous-
classe de Objet. Objet na pas de superclasse, alors que Classe
est sa propre instance. Objet est la racine de larbre dhritage,
tandis que Classe est la racine de larbre dinstanciation. Toute
classe doit donc hriter indirectement de Objet, et tre linstance
de Classe ou dune classe drive de Classe. Ce dernier point
correspond la cration de mtaclasses, sans les contraintes
imposes par Smalltalk-80. Dans la figure 20, Pile et Tour ont la
mme mtaclasse alors quavec Smalltalk-80, chacune delles
aurait sa propre mtaclasse. Dans cet exemple, il est utile de
navoir quune mtaclasse car la mme mthode dinstanciation
convient aux deux classes. Dun autre ct, le modle de
Smalltalk-80 permet de rendre les classes transparentes
lutilisateur grce la bijection entre classes et mtaclasses, ce
qui nest pas le cas dObjVLisp.
96 Les langages objets

4.7 CONCLUSION
Smalltalk est sans conteste le langage qui est lorigine du
succs du modle des objets. Trs rapidement, le langage a t
valid par la ralisation dapplications importantes, en
particulier lenvironnement de programmation Smalltalk. De
leur ct, les extensions de Lisp par les objets ont permis
dexprimenter et de mieux comprendre les mcanismes des
langages objets.

La puissance de Smalltalk est aussi sa principale faiblesse :


avec la liaison dynamique et labsence de typage statique, il est
impossible de sassurer de la correction dun programme avant
son excution, ni mme aprs. De plus, labsence de mcanisme
de protection des accs (toute mthode est accessible par tout le
monde) najoute pas la scurit de programmation. Des
extensions de Smalltalk ont introduit avec succs la dclaration
des classes des arguments et des variables locales. Dans CLOS,
les types des arguments des mthodes doivent tre dclars.
Dans les deux cas, la perte de fonctionnalit est minime, et, dans
CLOS, le typage permet mme dintroduire des mthodes
gnriques et daugmenter ainsi la puissance du langage.

Lautre faiblesse de Smalltalk et des langages interprts en


gnral est le manque defficacit lexcution. L encore, de
nombreux travaux ont permis daugmenter les performances de
faon spectaculaire. Des mesures ont mme montr que, pour
certaines applications, la diffrence de performance entre
Smalltalk et un langage objets typ et compil ntait pas
significative. Dans dautres cas, la diffrence est rdhibitoire, ce
qui ne fait que confirmer quil nexiste pas de langage
universel. Smalltalk en tout cas reste un langage privilgi pour
dcouvrir les concepts des langages objets, mais aussi pour
dvelopper des prototypes et, dans certains cas, des applications
finales.
Chapitre 5

PROTOTYPES
ET ACTEURS
Ce chapitre prsente deux variations importantes des ides de
base des langages objets. Les langages de prototypes font
disparatre la diffrence entre classes et instances en introduisant
la notion unique dobjet prototype. Ils remplacent la notion
dhritage par celle de dlgation. Les langages dacteurs
gnralisent la notion denvoi de message pour ladapter la
programmation parallle : lenvoi de message nest plus une
invocation de mthode, mais une requte envoye un objet.

5.1 LANGAGES DE PROTOTYPES


Les langages objets que nous avons prsents jusqu
prsent taient tous fonds sur les notions de classe, dinstance
et dhritage. Ces trois notions induisent deux relations entre les
entits du langage : la relation dinstanciation entre un objet et
sa classe, et la relation dhritage entre une classe et sa classe de
base. Pour distinguer ces langages objets classiques des
98 Les langages objets

langages de prototypes, nous appellerons les premiers langages


de classes.

Les premiers travaux sur les langages de prototypes datent de


1986 ; ils sont dus Henry Lieberman du MIT, qui la mme
poque a aussi travaill sur les langages dacteurs. Le langage
qui a inspir cette prsentation sappelle Self, cr et dvelopp
depuis 1987 par David Ungar et Randall Smith luniversit de
Stanford. Il reprsente ltape la plus avance dans le domaine
des langages de prototypes.

Prototypes et clonage

Dans un langage de prototypes, il ny a pas de diffrence


entre classes et instances : tout objet est un prototype qui peut
servir de modle pour crer dautres objets. Lopration qui
permet de crer un nouvel objet partir dun prototype
sappelle le clonage, et consiste recopier lobjet clon.

Dans un prototype, ltat et le comportement sont confondus :


il ny a pas de diffrence entre champs et mthodes, appels
indistinctement cases ( slots en anglais). Pour accder au
champ x, un prototype senvoie le message x. Pour modifier le
champ x, il senvoie le message x: avec la nouvelle valeur en
argument.

Nous dclarons un prototype par une liste de couples nom de


case / valeur, entoure daccolades. Les champs ont pour valeur
une expression tandis que les mthodes ont pour valeur un bloc
(not entre crochets, comme en Smalltalk). Un prototype de pile
aura ainsi laspect suivant :
Pile {
pile Tableau cloner.
sommet 0.
Empiler: unObjet [ sommet: (sommet + 1).
pile en: sommet mettre: unObjet ].
Dpiler [ sommet: (sommet - 1) ].
Sommet [ pile en: sommet ].
}
Prototypes et acteurs 99

Pile P1 P2

pile pile 10 pile 10 20


sommet 0 sommet 1 sommet 2
Initialiser Initialiser Initialiser
Dpiler Dpiler Dpiler
Sommet Sommet Sommet

Figure 21 - Le prototype Pile et deux clones

Les cases pile et sommet sont des champs. Leurs valeurs


correspondent aux valeurs initiales la cration du prototype.
Les messages daccs pile et s o m m e t , et les messages
daffectation pile: et sommet: sont implicitement crs. Les
autres cases sont des mthodes. Comme tous les accs aux
champs se font par messages, la pseudo-variable self est le
receveur implicite des messages. La mthode Dpiler pourrait
scrire sous la forme :
Dpiler [ self sommet: (self sommet - 1) ].

Dans cet exemple, Pile est un prototype, donc un objet


directement utilisable. Nous allons utiliser Pile comme un
modle pour crer et manipuler deux piles (figure 21) :
p1 Pile cloner.
p1 Empiler: 10.
x p1 Sommet. -- x vaut 10
p2 p1 cloner. -- p2 contient dj 10
p2 Empiler: 20.

Dans un langage de classes, une classe contient une


description de ses instances. Dans un langage de prototypes, tout
objet est un exemplaire qui peut tre reproduit par clonage.
Comme on le voit dans lexemple ci-dessus, ce mcanisme
simplifie linitialisation des objets : il suffit dinitialiser
correctement le prototype qui sert de modle. titre de
comparaison, Smalltalk exige de redfinir la mthode
100 Les langages objets

dinstanciation dfinie dans la mtaclasse ; avec les langages


objets typs, il faut introduire des mcanismes spcifiques tels
que les constructeurs de C++.

La dlgation

Le clonage consiste en la duplication exacte dun prototype


dans son tat courant. Cela signifie que ltat et le
comportement sont copis et quil ny a pas de lien entre
lobjet qui sert de modle et lobjet rsultant du clonage,
comme illustr dans la figure 21. Il ny a donc pas de possibilit
de partage entre les objets. Dans les langages de classes, le
partage existe deux niveaux :
par le lien dinstanciation entre un objet et sa classe, toutes
les instances dune classe partagent le mme comportement,
dcrit dans la classe.
par le lien dhritage entre une classe et sa superclasse, les
classes drives partagent les descriptions contenues dans
leurs superclasses.

Dans les langages de prototypes, un mcanisme unique, la


dlgation, permet des objets de partager des informations. Un
objet peut dlguer un autre objet, appel parent, les messages
quil ne comprend pas. Dans lexemple de la pile, nous allons
partager les mthodes Empiler, Dpiler et Sommet en les mettant
dans un prototype part, qui deviendra le parent de tous les
clones de la pile. Lorsque lun de ces messages sera envoy un
clone de la pile, il sera dlgu son prototype, dans ce cas
protoPile.

protoPile {
Empiler: unObjet [ sommet: (sommet + 1).
pile en: sommet mettre: unObjet ].
Dpiler [ sommet: (sommet - 1) ].
Sommet [ pile en: sommet ].
}

Le prototype de la pile scrit maintenant comme suit :


Prototypes et acteurs 101

protoPile Pile

Empiler pile
Dpiler sommet 0
Sommet

P1 P2

pile 10 pile 10 20
sommet 1 sommet 2

Figure 22 - Partage de mthodes avec les prototypes.


Les flches noires indiquent le parent (qui est un champ).
Les flches blanches indiquent les oprations de clonage

Pile {
parent protoPile.
pile Tableau cloner.
sommet 0.
}

Lorsque lon clone un prototype, les objets crs ont le mme


parent que leur prototype. Dans notre exemple, les clones de
Pile ont pour parent protoPile. Lexemple dutilisation vu plus
haut est toujours valable, mais le schma des objets lexcution
change, comme le montre la figure 22. Lorsque lon envoie le
message Empiler p1, il est dlgu son parent protoPile.

Dans cet exemple, le couple (Pile, protoPile) joue le rle


dune classe dans un langage de classes. Le lien dinstanciation
entre un objet et sa classe est ralis par la dlgation.
Linstanciation se fait par clonage, mais on pourrait aisment
102 Les langages objets

simuler le mcanisme des langages de classe en dfinissant dans


protoPile la mthode Nouveau, qui aurait pour valeur
[ Pile cloner].

Cet exemple montre galement pourquoi laccs aux champs


se fait par message : dans les corps des mthodes de protoPile,
on fait rfrence des champs (sommet, pile) qui sont dclars
dans Pile, donc inconnus de protoPile.

Dans la suite, nous utiliserons le terme classe pour parler


dun prototype qui contient exclusivement des mthodes. Il faut
nanmoins garder lesprit quune classe nest pas une notion
distincte dans les langages de protoypes.

Simuler lhritage avec la dlgation

Nous allons maintenant illustrer lutilisation de la dlgation


pour simuler lhritage. Reprenons pour cela lexemple des
Tours de Hanoi. Une tour est une pile qui doit contrler la taille
des objets empils. On cre donc un prototype Tour qui a pour
parent le prototype protoTour, qui a lui-mme pour parent
protoPile.

protoTour {
parent protoPile.
Empiler: unObjet [
unObjet < Sommet
siVrai: [ parent Empiler: unObjet ]
siFaux: [ Empiler: objet trop grand crire ]
].
}
Tour (Pile cloner) parent: protoTour.

Nous avons dfini dans ce nouveau prototype une mthode


Empiler: qui, selon la taille de lobjet, demande son parent de
raliser lempilement ou affiche un message derreur. Le
prototype Tour est cr par clonage du prototype Pile, en
changeant son parent. Lutilisation de Tour est illustre par
lexemple suivant et la figure 23.
Prototypes et acteurs 103

protoPile Pile

Empiler pile
Dpiler sommet
Sommet

protoTour Tour t

Empiler pile pile


sommet sommet

Figure 23 - Simulation de lhritage par la dlgation.


Les flches ont la mme signification que pour la figure 22

t Tour cloner.
t Empiler: 10.
t Empiler: 20. -- Empiler: objet trop grand

Lexemple de la pile que nous venons de prsenter permet de


faire le parallle entre les langages de prototypes et les langages
de classes. Mais lintrt des prototypes est dtendre les
possibilits des langages de classes. Les prototypes permettent
ainsi, entre autres, de crer des objets dots de comportements
exceptionnels, davoir des champs calculs, et de faire de
lhritage dynamique. Nous allons maintenant illustrer ces
diffrentes possibilits.

Comportements exceptionnels

Dans lexemple de la tour, si notre application utilise une


seule tour, on peut crer un objet qui a le comportement dune
tour sans pour autant crer la classe correspondante. Il suffit de
redfinir la case Empiler: dans lobjet lui-mme :
104 Les langages objets

t {
parent protoPile.
pile Tableau cloner.
sommet 0.
Empiler: unObjet [
unObjet < Sommet
siVrai: [ parent Empiler: unObjet ]
siFaux: [ Empiler: objet trop grand crire ]
].
}

t Empiler: 10.
t Empiler: 20. -- Empiler: objet trop grand

Cet exemple montre comment crer des objets avec des


comportements exceptionnels. Les objets vrai et faux de
Smalltalk sont un autre exemple dapplication : l o nous
avions cr deux classes Vrai et Faux, avec chacune une instance
unique, il nous suffit de crer deux prototypes vrai et faux,
contenant chacun une version de la mthode siVrai:siFaux:. On
peut noter que de tels objets peuvent tre clons, les clones
disposant galement du comportement exceptionnel.

Une autre application des comportements exceptionnels est la


mise au point de programme. Si lon veut suivre le
comportement dun objet prcis, on peut dfinir une mthode
dans lobjet de la faon suivante (nous utilisons la mthode
ajoute: qui permet dajouter des cases dans un objet) :
p Pile cloner ajoute: {
Empiler: unObjet [
p Empiler crire.
parent Empiler: unObjet
]
}

Tout empilement sur p provoquera un message. Dans un


langage de classes, lajout dune trace dans la mthode Empiler
de la classe Pile provoquerait lcriture du message pour tout
objet de la classe Pile.
Prototypes et acteurs 105

Champs calculs

Laccs aux champs dun prototype par envoi de message


permet de dfinir des champs dont la valeur est calcule et non
pas stocke dans lobjet. Pour illustrer cela, dfinissons un
prototype p r o t o P o i n t qui contient des mthodes de
manipulation de points, et deux prototypes de points : lun dont
la position est stocke en coordonnes cartsiennes (Cartsien),
lautre en coordonnes polaires (Polaire) :
protoPoint {
crire [ x crire. , crire. y crire ].
+: p [ cloner x: (x + p x) y: (y + p y) ].
}
La mthode +: cre un nouveau point dont les coordonnes
sont la somme des coordonnes du receveur et de largument.

Cartsien { Polaire {
parent protoPoint. parent protoPoint.
x 0. rho 0.
y 0. thta 0.
} }

Malheureusement, le prototype Polaire est inutilisable car les


mthodes de protoPoint utilisent les champs x et y. Pour
remdier cette situation, il suffit dajouter les mthodes x, y, x:
et y: Polaire pour simuler les champs absents, grce aux
quations suivantes :
x = cos = (x2 + y2)
y = sin = atan (y / x)

De lextrieur, tout ce passe comme si Polaire avait les


champs x et y , qui sont en ralit calculs partir des
coordonnes polaires stockes dans lobjet.

Polaire {
parent protoPoint.
rho 0.
thta 0.
106 Les langages objets

x [ rho * thta cos ].


y [ rho * thta sin ].
x: val [ rho: (val * val + y * y) sqrt. thta: (y / val) atan ].
y: val [ rho: (x * x + val * val) sqrt. thta: (val / x) atan ].
}

On pourrait de faon similaire ajouter les champs calculs rho


et thta au prototype Cartsien. Cela permettrait dutiliser les
coordonnes les plus adquates dans les mthodes de
protoPoint.

Hritage dynamique

Le parent dun prototype est une case similaire aux autres,


lexception de son rle particulier pour la dlgation lors de
lenvoi de messages. Rien ninterdit donc de modifier la valeur
de la case qui contient le parent dun objet aprs la cration de
celui-ci : cest lhritage dynamique. Ainsi, en utilisant les
dfinitions de P i l e et de T o u r vues plus haut, on peut
transformer une tour en pile en affectant sa case parent :
t Tour cloner.
t Empiler: 10.
t Empiler: 20. -- Empiler: objet trop grand
t parent: Pile. -- la tour devient une pile
t Empiler: 20. -- OK

Les applications de cette technique sont multiples. Par


exemple, il arrive que la classe dun objet ne puisse tre
dtermine compltement sa cration, ou quelle soit amene
changer lors de la vie de lobjet. Lhritage dynamique permet
de prciser la classe au fur et mesure des connaissances
acquises. Par exemple, dans un systme graphique, des
oprations entre objets graphiques permettent de crer de
nouveaux objets. Si un objet ainsi cr se trouve tre un objet
rgulier comme un rectangle, il peut changer de parent pour
utiliser des mthodes plus efficaces que celles dfinies sur un
objet quelconque. Inversement, si un rectangle est transform
par une rotation, il devient un polygone, et doit changer de
parent en consquence.
Prototypes et acteurs 107

Lhritage dynamique est galement utile lors de la mise au


point dun programme : pour observer un objet, on lui affecte
comme parent un prototype qui trace les oprations effectues.
On peut galement tester une nouvelle implmentation dune
classe en affectant, en cours dexcution, la nouvelle classe au
parent dun objet.

Conclusion

En abolissant les diffrences entre classe et instance, et en


unifiant les champs et les mthodes, les langages de prototypes
ouvrent de nouvelles portes aux langages objets liaison
dynamique.

De faon assez surprenante, limplmentation dun langage


de prototypes peut tre plus efficace que celle dun langage tel
que Smalltalk. Ceci ncessite nanmoins la mise en uvre de
techniques assez complexes, qui consistent pour lessentiel
garder dans des caches les rsultats des recherches de mthodes
pour optimiser les envois de messages, et compiler diffrentes
versions dune mthode pour des contextes dappels diffrents.

Il nen reste pas moins que les langages de prototypes sont


des langages non typs, donc sans aucun contrle de la validit
dun programme avant son excution. Autant il est envisageable
dajouter des dclarations de type dans un langage comme
Smalltalk, autant cela est illusoire dans un langage de
prototypes. En effet, la notion de type, qui correspond celle de
classe dans un langage de classes, na pas vraiment dquivalent
dans un langage de prototypes. Si lon considre que le type
dun objet est son parent, tout typage statique est impossible car
le type de lobjet peut changer durant sa vie. Par ailleurs, la
structure dun objet peut aussi changer par ajout de cases, de
telle sorte quutiliser la structure dun objet comme type est
galement impossible.

En labsence de moyens de vrification statique des


programmes, les langages de prototypes restent donc rservs
essentiellement au prototypage
108 Les langages objets

5.2 LANGAGES DACTEURS


Les langages dacteurs sont ns au MIT des travaux de Carl
Hewitt dans les annes 70 avec le langage Plasma. Au dbut des
annes 80 Henry Liebermann, du MIT, a dvelopp ACT1, puis
Akinori Yonezawa de lInstitut de Technologie de Tokyo a
introduit ABCL/1.

Lobjet des langages dacteurs est de fournir un modle de


calcul parallle fond sur des entits indpendantes et
autonomes communiquant par messages. Ces entits, appeles
acteurs, sont composes dun tat et dun filtre. Ltat est
constitu de variables locales et de rfrences dautres acteurs,
tandis que le filtre est une suite de modles de messages
auxquels lacteur peut rpondre. Chaque acteur est autonome :
lorsquun message arrive, il vrifie sil correspond un modle
de son filtre. Si cest le cas, lacteur receveur excute le bloc
dinstructions correspondant. Sinon, lacteur dlgue le
message un autre acteur, appel son mandataire ( proxy en
anglais). Ce mcanisme de dlgation est similaire celui des
langages de prototypes, et nous ne reviendrons pas dessus.

Les seules actions que peut effectuer un acteur sont lenvoi de


message, la cration de nouveaux acteurs, et sa transformation
en un autre acteur. Lenvoi de message est asynchrone : lacteur
ne se soucie pas de ce quil advient des messages quil envoie.
Cet envoi asynchrone introduit le paralllisme de manire
naturelle : lacteur continue son activit pendant que le message
envoy est trait par son destinataire. Comme chaque acteur est
squentiel, il dispose dune bote aux lettres dans laquelle sont
stocks les messages qui arrivent pendant quil traite un
message.

La cration dacteur est simple : un acteur peut crer un autre


acteur, dont il spcifie le mandataire, ltat, et le filtre. La
transformation dun acteur est similaire sa cration, la
diffrence que le nouvel acteur remplace le prcdent, cest--
dire quil rcupre sa bote aux lettres. Dans le modle introduit
par Gul Agha, un acteur peut se transformer avant davoir
Prototypes et acteurs 109

termin le traitement du message en cours. Dans ce cas, un


acteur peut traiter plusieurs messages en parallle : il lui suffit,
lorsquil reoit un message, de commencer par spcifier son
remplaant. Celui-ci pourra immdiatement traiter le prochain
message en attente. La possibilit de traiter des messages en
parallle interdit de modifier ltat de lacteur. Ceci justifie la
ncessit de fournir explicitement un remplaant, qui est
gnralement une copie modifie de lacteur initial.

Lenvoi asynchrone de messages, sil introduit naturellement


le paralllisme, pose un problme : comment envoyer un
message et obtenir un rsultat en retour ? La rponse consiste
transmettre une continuation avec le message. Une continuation
dsigne lacteur auquel le receveur dun message devra
transmettre sa rponse. Un acteur peut recevoir la rponse dun
message en se mentionnant comme continuation du message,
mais il peut aussi mentionner un autre acteur qui saura traiter le
rsultat mieux que lui.

Considrons par exemple les trois acteurs suivants : le lecteur


lit des expressions au clavier, l v a l u a t e u r value des
expressions, et limprimeur affiche des valeurs. Le lecteur,
lorsquil a lu une expression, envoie un message lvaluateur
avec comme contenu lexpression valuer et comme
continuation limprimeur. Ainsi, lvaluateur transmettra
directement le rsultat afficher limprimeur. Dans un modle
classique, le lecteur demanderait lvaluation lvaluateur,
recevrait la rponse, et la transmettrait limprimeur.

Avec cet exemple, on pourrait penser que la continuation est


inutile, puisque lvaluateur envoie toujours sa rponse
limprimeur. Ce nest pas le cas : lvaluateur peut, si
lexpression est complexe, senvoyer des messages avec des
sous-expressions valuer, en se spcifiant comme sa propre
continuation. Un autre acteur, qui lit par exemple dans un
fichier, peut envoyer des messages lvaluateur avec comme
continuation un imprimeur qui crit dans un fichier de sortie
(figure 24).
110 Les langages objets

val: expr Imprimeur val: expr self impr: rsultat

Evaluateur

Lecteur Imprimeur

fichier fichier

Figure 24 - Envois de messages avec continuations

Programmer avec des acteurs

Pour les exemples de cette section, nous avons adapt la


syntaxe utilise prcdemment pour les prototypes. Un acteur
est dcrit par son nom, ventuellement suivi de son tat et de son
filtre. Le filtre est un ensemble de couples <modle de message /
action>. Un modle est un nom de message, avec des arguments
et une continuation ventuelle, indique par une flche .
La cration dacteurs et lenvoi de message ont la forme
suivante :
crer acteur (tat1, tat2, tatn)
acteur msg1: arg1 msg2: arg2 msgn: argn continuation

La figure 25 montre la reprsentation dun acteur : la flche


horizontale reprsente la vie de lacteur, les lignes brises
reprsentent les envois de messages et les lignes pointilles
reprsentent les crations dacteurs.

Lorsquun acteur reoit un message, les modles de son filtre


sont compars au message reu. Le modle qui ressemble le
plus au message reu est choisi, et laction correspondante est
Prototypes et acteurs 111

rception de message
acteur vie de l'acteur

tat
envoi de message

cration d'acteur

Figure 25 - Reprsentation dun acteur

active. Si aucun modle ne convient, le message est transmis au


mandataire, sil y en a un ; sinon il y a erreur.

Programmer avec des acteurs exige doublier tout ce que lon


sait de la programmation pour apprendre de nouvelles
techniques spcifiques du paralllisme. Prenons lexemple
simple de la factorielle, que chacun sait crire sous la forme
dune fonction rcursive. Voici comment on ralise le calcul
dune factorielle avec des acteurs :
acteur factorielle
filtre
fact: 0 r [ r envoie: 1].
fact: i r [ cont crer mult (i, r).
self fact: (i - 1) cont].

acteur mult
tat val rec
filtre
envoie: v [ rec envoie: (v * val)].

Lacteur factorielle a deux modles de messages, qui


concernent tous les deux le message fact: avec une continuation.
Le premier modle ne reconnat le message fact: que lorsque
son argument est nul ; le second reconnat les autres messages
fact:. Lacteur factorielle utilise un autre acteur, mult, pour
laider faire son calcul. Ltat de mult est constitu par un
entier val et un acteur rec. Lorsquil reoit le message envoie:, il
112 Les langages objets

fact: 3 res

fact: 2 mult1 fact: 1 mult2 fact: 0 mult3

factorielle
envoie:
1
mult3
1, mult2
envoie: 1
mult2
2, mult1
envoie: 2
mult1
3, res1
envoie: 6

res

Figure 26 - Calcul de la factorielle

renvoie le message envoie: lacteur rec, avec comme argument


le produit de val et de la valeur reue. En dautres termes, mult
ralise une multiplication et transmet le rsultat un acteur qui a
t spcifi sa cration.

Lorsque lacteur factorielle reoit un message lui demandant


de calculer la factorielle de i et de transmettre le rsultat la
continuation r, il commence par crer un acteur mult. Cet acteur
multipliera par i la valeur qui lui sera transmise, et enverra le
rsultat r. Ensuite, lacteur factorielle senvoie un message lui
demandant de calculer la factorielle de i-1 et de transmettre le
rsultat lacteur m u l t quil vient de crer. Cet acteur
multipliera donc la factorielle de i-1 par i, produisant le rsultat
escompt. Lorsque factorielle doit calculer la factorielle de 0, il
envoie directement 1 la continuation du message, ce qui
Prototypes et acteurs 113

fact: 3 r1 fact: 4 r2

factorielle

6 24

Figure 27 - Calcul simultan de plusieurs factorielles

termine le calcul en vitant lenvoi infini de messages de


factorielle lui-mme.

La figure 26 visualise le calcul dune factorielle. Il y a


cration dun ensemble dacteurs mult i, un pour chaque tape
du calcul. Ces acteurs sont inactifs jusqu rception du message
envoie:. Le calcul se dclenche en chane lorsque factorielle
envoie le message envoie: mult3.

Le modle des acteurs nous a oblig transformer la


rcursion en un ensemble dacteurs qui reprsente le
droulement du calcul. Dans cet exemple, le calcul est
strictement squentiel. Nanmoins, lacteur factorielle est
capable de calculer plusieurs factorielles simultanment. En
effet, observons ce qui se passe lorsquil reoit deux messages
fact: (figure 27) : les deux calculs senchevtrent sans se
mlanger, car les messages transportent linformation suffisante
pour le calcul quils sont en train deffectuer, sous la forme de
continuations.

Il existe dautres techniques de programmation avec des


acteurs, que nous ne dtaillerons pas ici, part la jointure de
continuations dont nous donnerons un exemple plus loin.
114 Les langages objets

Envoi de messages

Les langages dacteurs apportent aux langages objets une


nouvelle vision de lenvoi de message. En fait, il ny a que dans
les langages dacteurs que le terme denvoi de message est
correct : dans les autres langages, il sagit dinvocation de
procdures ou fonctions. La communication asynchrone, que
nous avons utilise jusqu prsent, nest pas la seule disponible
dans les langages dacteurs.

ABCL/1, par exemple, dispose de deux autres types de


communication. Le premier, la communication synchrone,
correspond lenvoi de message avec attente de rponse. Dans
ce cas la continuation est obligatoirement lmetteur du
message. La communication synchrone bloque lmetteur
jusqu rception du message. Lautre type de communication
dABCL/1, la communication anticipe, permet de lever cette
contrainte. Au lieu dtre bloqu dans lattente de la rponse,
lacteur continue fonctionner. Pour savoir si la rponse est
disponible, il interroge le receveur du message. De cette faon,
un acteur peut lancer des messages et collecter les rponses
lorsquil en a besoin.

Par ailleurs ABCL/1 offre deux modes de transmission des


messages : le mode ordinaire, dans lequel les messages sont
ajouts dans la bote aux lettres du receveur, et le mode express.
Lorsquun message express est envoy un acteur, celui-ci est
interrompu pour traiter ce message immdiatement. Sil tait
dj en train de traiter un message express, le message reu est
mis dans la bote aux lettres des messages express, qui est
toujours traite avant la bote aux lettres des messages
ordinaires.

Les diffrents types de communication comme les modes de


transmissions sont destins faciliter la programmation avec des
acteurs qui reste pourtant assez droutante. Ainsi les messages
express permettent de raliser des interruptions. Supposons
quun acteur reprsente un tableau, et quun message permette
de trouver un lment dans le tableau. Lacteur dcide de
Prototypes et acteurs 115

rpartir le travail entre plusieurs acteurs qui cherchent dans des


parties disjointes du tableau. Ds quun acteur a trouv
llment cherch, il est inutile pour les autres de poursuivre.
Lacteur principal peut alors les interrompre par lenvoi dun
message express. Sans ce moyen, chaque acteur devrait
dcouper sa recherche en tapes lmentaires, en senvoyant des
messages lui-mme afin que le message dinterruption puisse
tre pris en compte.

Objets et acteurs

On peut se demander dans quelle mesure les langages


dacteurs sont des langages objets. Un acteur est un objet dans
le sens o il dtient un tat et un comportement, mais,
contrairement un objet, il est actif et sapparente plutt un
processus. Cela apparat clairement dans lexemple de la
factorielle : lacteur est un objet qui calcule une factorielle, alors
quun langage objets classique verrait la factorielle comme un
message envoy un nombre. Les acteurs sont donc aptes
reprsenter un comportement ou un calcul, linstar des
fonctions, ce que les objets sont incapables de faire. Mais les
acteurs peuvent aussi reprsenter un tat et des mthodes
associes, linstar des objets. De tels acteurs peuvent tre
amens crer des acteurs de calcul pour rpondre un
message. Lexemple ci-dessous illustre cet aspect.

Il sagit de reprsenter le jeu des Tours de Hanoi, et de le


rsoudre. Nous aurons besoin dans cet exemple de listes de type
Lisp. Une liste est note entre accolades. Nous supposons
quune liste rpond aux messages synchrones ajoute:, car et
cdr, et quelle peut tre parcourue par le message rpter: qui
prend en argument un bloc avec un argument. Nous dnotons
les messages synchrones en utilisant le symbole comme
continuation. Les messages synchrones peuvent retourner une
valeur en utilisant loprateur .

Nous allons utiliser un acteur Tour pour reprsenter une tour,


dont ltat contient la pile des disques. Un acteur H a n o i
reprsentera lensemble du jeu.
116 Les langages objets

acteur Tour
tat pile sommet
filtre
Empiler: x [ pile en: sommet mettre: x .
sommet sommet + 1 ]
Dpiler [ sommet sommet - 1 ]
Sommet [ pile en: sommet ]

Lacteur Tour est ici une pile : nous navons pas insr le test
qui compare la taille de lobjet empil avec le sommet courant.
Ceci nest pas important dans cet exemple, car la rsolution par
programme des Tours de Hanoi assure que les rgles du jeu sont
respectes. Sommet est un message synchrone qui retourne
lobjet en sommet de pile. Nous avons suppos que lacteur qui
reprsente la pile sait rpondre aux messages daccs en: et
en:mettre:. Lempilement utilise un message synchrone.

acteur Hanoi
tat gauche droite centre nd
filtre
Initialiser
[ (1 nd) rpter [ :i | gauche Empiler: (nd - i) ] ]
dplacer: dp vers: arr
[ arr Empiler: (dp Sommet ). dp Dpiler ]
Jouer
[ jh crer JoueHanoi (self).
jh dplacer: nd de: gauche vers: droite
par: centre tag: 1 jh ]

Lacteur Hanoi reprsente les Tours de Hanoi. Initialiser


permet de mettre nd disques de tailles dcroissantes sur la tour
de gauche. dplacer:vers: dplace un disque de la tour passe
en premier argument vers celle passe en second argument ; il
envoie le message synchrone Sommet la tour de dpart, empile
la valeur retourne sur la pile darrive, et dpile la tour de
dpart. Jouer permet de lancer la rsolution du jeu. Jouer cre
un acteur JoueHanoi charg de rsoudre le jeu. Rappelons
lalgorithme squentiel rcursif qui rsout les Tours de Hanoi :
Prototypes et acteurs 117

-- dplacer n disques de la tour dp vers la tour arr


-- en utilisant la tour intermdiaire inter
procdure Hanoi (n : entier; dp, arr, par : tour) {
si n 0 alors {
Hanoi (n-1, dp, inter, arr);
DplaceDisque (dp, arr);
Hanoi (n-1, inter, arr, dp);
}
}

Avec les acteurs, la difficult provient de la rsolution parallle


qui doit nanmoins produire une liste o r d o n n e de
dplacements de disques. Selon la technique utilise pour
calculer la factorielle, et laide dune jointure de
continuations, nous allons crer des acteurs qui reprsentent les
tapes du calcul, cest--dire les sous-squences de
dplacements de disques.
acteur JoueHanoi
tat hanoi
filtre
dplacer: 1 de: D vers: A par: M tag: t cont
[ cont tag: t liste: {D A} ]
dplacer: n de: D vers: A par: M tag: t cont
[ c crer Jointure (cont, t, {D A}, 0).
self dplacer: n-1 de: D vers: M par: A tag: t*2 c.
self dplacer: n-1 de: M vers: A par: D tag: t*2+1 c.
]
tag: t liste: listedpl
[ listedpl rpter:
[ :d | hanoi dplacer: (d car ) vers: (d cdr ) ]
]

Lorsquil reoit le message de rsolution dplacer:de:vers:


par:tag:, lacteur JoueHanoi cre un acteur Jointure pour la
jointure des continuations et senvoie deux messages de
rsolution pour les deux sous-problmes. Lacteur de jointure
est initialis avec le dplacement mdian et la continuation de
JoueHanoi. Il attend de recevoir les deux listes de dplacements,
118 Les langages objets

les combine avec le dplacement mdian, et envoie le rsultat


la continuation. Voyons maintenant lacteur de jointure :
acteur Jointure
tat cont t listedpl attente
filtre
tag: t*2 liste: l
[ listedpl l ajoute: listedpl . self envoyer ]
tag: t*2 +1 liste: l
[ listedpl listedpl ajoute: l . self envoyer ]
envoyer
[ attente attente+1.
(attente = 2) siVrai: [ cont tag: t liste: listedpl ] ]

Afin de combiner les listes de dplacements correctement,


lacteur de jointure doit pouvoir distinguer les deux listes quil
reoit. Pour cela, les messages de rsolution transportent une
tiquette, appele tag, qui numrote chaque rsolution de faon
unique : la rsolution dtiquette n dclenche deux rsolutions
dtiquettes 2*n et 2*n+1. Lacteur de jointure est initialis
avec ltiquette de la rsolution pour laquelle il a t cr ; il
peut donc dterminer lorigine des listes quil reoit et
combiner les dplacements en consquence. Le message
e n v o y e r permet denvoyer le dplacement final la
continuation, lorsque les deux sous-listes ont t reues.

Le message tag:liste: est envoy par JoueHanoi lorsquil a un


seul disque dplacer, et par Jointure lorsquil a combin les
listes avec le dplacement mdian. Il est reu soit par Jointure,
auquel cas il contient les sous-listes de dplacements, soit par
JoueHanoi lui-mme lorsque la rsolution est termine. Dans ce
cas, la valeur de ltiquette nest plus utile. Lorsque JoueHanoi
reoit la rsolution finale, il numre la liste des dplacements et
envoie H a n o i des messages de dplacement de disque
dplace:vers:. Ces envois de messages sont synchrones pour
assurer leur traitement dans lordre dmission ; sinon, tout le
travail prcdent aurait t inutile.

Lexemple ci-dessous initialise un acteur Hanoi avec deux


disques et lance une rsolution, qui est illustre figure 28.
Prototypes et acteurs 119

Jouer

tours
G, C, D, 2
dplacer: 2
de: G vers: D par: C dplacer:
Hanoi G vers: C
tag: 1 jh
dplacer:
dplacer: 1 G vers: D
de: C vers: D par: G
tag: 3 c dplacer:
C vers: D

dplacer: 1
de: G vers: C par: D
tag: 2 c
jh
tours
tag: 2 tag: 3
JoueHanoi liste: {GC} liste: {CD}
tag: 1 liste:
{GC}{GD}{CD}
c
tours, 1,
{GD}, 0

Jointure
envoyer envoyer

Figure 28 - Rsolution des Tours de Hanoi

tours crer Hanoi (


crer Tour (crer Tableau, 0), -- gauche
crer Tour (crer Tableau, 0), -- centre
crer Tour (crer Tableau, 0), -- droite
2). -- nd
tours Initialiser. tours Jouer.
120 Les langages objets

Le degr de paralllisme obtenu est assez faible : lacteur de


jointure fonctionne en parallle avec lacteur JoueHanoi, mais
cest ce dernier qui fait lessentiel du travail. Si lon a n disques,
il y a cration dun seul acteur JoueHanoi, et de 2 n-1 -1 acteurs
de jointure. Le temps de rsolution est exponentiel en fonction
de n, car lacteur JoueHanoi senvoie 2n-1 messages quil traite
squentiellement.

On pourrait augmenter le paralllisme en crant un acteur


JoueHanoi chaque dcomposition du problme. Pour n
disques, il y aurait cration de 2*(n-1) acteurs JoueHanoi et de
2 n-1 -1 acteurs de jointure, et le temps de rsolution serait
linaire en fonction de n.

Conclusion

La programmation avec un langage dacteurs nest pas


simple, mais cela est vrai de tous les langages parallles. Par
contre, le modle des acteurs est facile comprendre, ce qui
nest pas le cas de tous les modles du paralllisme.

Les langages dacteurs sont plus proches des langages de


prototypes que des langages de classes : ils utilisent la
dlgation, et la cration dacteurs est proche du clonage. Cette
ressemblance a des raisons historiques : la plupart des langages
dacteurs ont t dvelopps au-dessus de Lisp, et ils sont
contemporains des premiers langages de prototypes. Il en
rsulte que les langages dacteurs ne sont pas typs, quils nont
pas de mcanismes de modularit, et quils emploient la liaison
dynamique. Les travaux sur les langages dacteurs se sont
focaliss essentiellement sur la smantique de lenvoi de
message, au dtriment de ces autres aspects.

Les langages dacteurs et les langages de prototypes explorent


des directions indpendantes qui se dmarquent du modle strict
des langages de classe. Ils permettent aussi de mieux
comprendre lessence de la programmation par objets, et lon
peut sattendre des retombes de ces travaux sur les langages
objets plus classiques.
Chapitre 6

PROGRAMMER
AVEC DES OBJETS
Ce chapitre prsente quelques techniques usuelles de program-
mation par objets et une bauche de mthodologie. Il se termine
par lexemple complet des Tours de Hanoi, qui complte les
classes Pile et Tour qui nous ont servi tout au long de ce livre.
Bien que ce chapitre sapplique aux langages objets typs
aussi bien quaux langages non typs, lexemple sera dvelopp
dans le langage que nous avons utilis au chapitre 3. Un certain
nombre de points seront donc spcifiques des langages typs.

Contrairement la programmation imprative ou fonction-


nelle classique, la programmation par objets est centre sur les
structures de donnes manipules par le programme. Le
dveloppement dun programme suit donc les trois phases
suivantes :
Identification des classes.
Dfinition du protocole des classes, cest--dire les en-ttes
des mthodes publiques (visibles de lextrieur des classes).
122 Les langages objets

Dfinition des champs et implmentation des corps des


mthodes. Dfinition ventuelle de mthodes prives
(visibles uniquement de lintrieur des classes).

Lidentification correcte des classes, lutilisation correcte de


lhritage et la bonne dfinition des protocoles sont
dterminants lorsque lon souhaite crer des classes rutilisables.
Aussi est-il important de comprendre et de pratiquer la
programmation par objets avant de lutiliser (pour des besoins
professionnels), afin den percevoir clairement, par
lexprimentation, les limites et les subtilits intrinsques.

6.1 IDENTIFIER LES CLASSES


Lidentification des classes dobjets, qui semble souvent aise,
ncessite en ralit une bonne pratique de la programmation par
objets. Il faut viter de dfinir trop peu de classes, qui
correspondent des fonctionnalits trop complexes, mais aussi
de dfinir trop de classes, qui entretiennent des relations
complexes entre elles. Le juste milieu est affaire dexprience.
Les mthodes de conception pour les langages objets sont
encore balbutiantes. Les mthodes de conception par objets (
ne pas confondre avec les prcdentes) sont plus rpandues,
mais elles ne sont pas toujours les mieux adaptes aux langages
objets. Certaines dentre elles par exemple ne prennent pas en
compte lhritage. Une bonne approche consiste aussi tudier
les bibliothques de classes fournies avec les langages ou
disponibles pour ceux-ci. La bibliothque de classes de
Smalltalk est ce titre trs instructive. Elle contient lensemble
des classes qui implmentent le systme dexploitation et
lenvironnement de programmation graphique du systme
Smalltalk.

Nous proposons de distinguer plusieurs catgories de classes.


Sans tre exhaustive, cette classification donne une ide des
diffrents rles que peut jouer une classe dobjets dans une
application.
Programmer avec des objets 123

Les classes atomiques reprsentent des objets autonomes,


cest--dire dont ltat vu de lextrieur ne dpend pas dautres
classes. Par exemple, des classes dobjets graphiques (rectangles,
cercles, etc.) ou gomtriques (points, vecteurs, etc.) sont des
classes atomiques. La classe des piles nest pas une classe
atomique car une pile renferme des objets auxquels on peut
accder.

Les classes composes sont des classes dont les instances sont
des assemblages de composants, ceux-ci tant accessibles de
lextrieur. Accessible signifie que lon peut avoir connaissance
des composants, mme si la classe contrle ou limite leur accs.
Par exemple, laccs aux composants peut tre en lecture seule,
ou bien par lintermdiaire de noms symboliques (indice,
chane de caractres). La classe des Tours de Hanoi est un
exemple de classe compose ; dans lexemple que nous
donnons plus loin dans ce chapitre, nous verrons que laccs
aux tours se fait de manire symbolique, par un type numr.

Les classes conteneurs sont un cas particulier de classes


composes. Une instance dune classe conteneur (un conteneur)
renferme une collection dobjets et fournit des mthodes pour
ajouter, enlever, rechercher des objets de la collection. Souvent,
une classe conteneur fournit galement un moyen dnumrer
les objets de la collection, souvent par lintermdiaire dune
classe active ou dun itrateur (voir ci-dessous). La classe des
piles est un exemple typique de classe conteneur.

Les classes actives sont des classes qui reprsentent un


processus plutt quun tat. En Smalltalk, les blocs sont des
classes actives, qui nous ont servi dans le chapitre 4 dfinir des
structures de contrle. Un autre exemple courant de classe active
sont les classes ditrateurs. Un itrateur est un objet qui permet
dnumrer les composants dun autre objet. En gnral, lobjet
itr est un conteneur. Une mthode de litrateur retourne le
prochain objet de lobjet numr. Litrateur sert stocker
ltat courant de lnumration, ce qui permet plusieurs
itrateurs dtre actifs simultanment sur le mme objet. Un
exemple ditrateur est prsent plus loin dans cette section.
124 Les langages objets

Les classes abstraites sont des classes qui ne sont pas prvues
pour tre instancies, mais seulement pour servir de racine une
hirarchie dhritage. En gnral, les classes abstraites nont pas
de champs. Leurs mthodes doivent tre redfinies dans les
classes drives, ou doivent appeler de telles mthodes. Une
classe abstraite sert dfinir un protocole gnral qui ne prjuge
pas de limplmentation des classes drives. Un bon gage
dextensibilit dun ensemble de classes est dinsrer des classes
abstraites en des points stratgiques de larbre dhritage.

Par exemple, la classe abstraite Collection dcrite ci-dessous


contient des mthodes dajout, de retrait, et de recherche dun
lment. Ces mthodes doivent tre virtuelles si le langage
impose la dclaration explicite de la liaison dynamique, comme
en C++. Les classes drives (Ensemble, Liste, Fichier, etc.),
doivent redfinir ces mthodes en fonction de leur
implmentation de la collection.

Collection = classe {
mthodes
procdure Ajouter (Objet);
procdure Retirer (Objet);
fonction Chercher (Objet) : boolen;
fonction Suivant (Objet) : Objet;
}

Une classe abstraite peut galement contenir des mthodes


dont le corps est dfini dans la classe abstraite, comme la
mthode AjouterSiAbsent ci-dessous :
procdure AjouterSiAbsent (o : Objet) {
si non Chercher (o) alors Ajouter (o);
}

En imposant un protocole sur ses classes drives, une classe


abstraite permet dobtenir une plus grande homognit entre
les classes. Par exemple, la classe Collection vite davoir une
mthode Ajouter dans Ensemble et une mthode Insrer dans
Liste : les deux mthodes devront sappeler Ajouter.
Programmer avec des objets 125

Une classe abstraite sert galement dfinir des classes


gnrales ( dfaut de gnriques) : soit une classe abstraite A et
une classe quelconque C ; en dclarant dans C des champs ou
des arguments de mthodes de type A, on pourra utiliser C avec
une plus grande gamme dobjets que si lon avait utilis une
classe concrte. titre dexemple, et partir de la classe
Collection dfinie ci-dessus, on peut construire une classe
gnrale Itrateur, alors quen labsence de classe abstraite, on
serait contraint de dfinir une classe ditrateurs pour chaque
classe conteneur.
Itrateur = classe {
champs
coll : Collection;
courant : Objet;
mthodes
procdure Initialiser (c : Collection) {
c := coll;
courant := coll.Suivant (NUL);
}
fonction Suivant () : Objet {
o : Objet;
o := courant;
si o NUL alors courant := coll.Suivant (courant);
retourner o;
}
}

Nous avons suppos ici que Collection.Suivant(NUL) retourne


le premier objet de la collection, et que Collection.Suivant(o)
retourne NUL lorsque o est le dernier lment de la collection.
NUL est un objet distingu qui sert ici simplifier lcriture.

Hritage ou imbrication ?

Le principal problme dans lidentification des classes est le


choix de la hirarchie dhritage. Il sagit de dterminer si une
classe doit hriter dune autre, et si oui de laquelle. Ici, les
langages typs sont plus contraignants que les langages non
typs car le choix de lhritage dterminera ce que lon peut
126 Les langages objets

faire des instances de la classe. Dans lexemple de la classe


Collection ci-dessus, si lon dfinit une classe qui nhrite pas
de Collection mais qui dfinit la mthode Suivant, on ne pourra
pas utiliser la classe Itrateur sur les objets de cette classe. Ce
serait possible dans un langage non typ, car tout ce que
demande la classe Itrateur lobjet itr est de rpondre au
message S u i v a n t . En consquence, le choix de larbre
dhritage est la fois plus difficile et plus dterminant dans les
langages objets typs.

Lhritage est un mcanisme puissant, ce qui signifie quil


peut tre utilis dans diffrents contextes. Lhritage peut servir
reprsenter la spcialisation et lenrichissement : cest ce pour
quoi il est utilis le plus souvent. Ainsi, dans les chapitres
prcdents, nous avons fait hriter la classe Tour de la classe Pile
car une tour est une pile spciale . Par contre, nous nous
sommes gards de faire hriter Pile dune hypothtique classe
Tableau, et nous avons prfr mettre le tableau dans la pile.

La relation dordre entre les classes qui est induite par


lhritage doit nous inciter utiliser lhritage lorsque les
protocoles des classes sont compatibles, et nous en dissuader
lorsque seulement les structures des classes sont compatibles. Le
protocole dune classe est compatible avec celui dune autre
classe sil est inclus dans celui-ci. De mme, la structure dune
classe est compatible avec celle dune autre classe si elle est
incluse dans celle-ci. Cest la compatibilit des protocoles qui
permet dutiliser lhritage non seulement pour la spcialisation
(cas dgalit), mais aussi pour lenrichissement. Une pile et une
tour ont le mme protocole : empiler, dpiler, lire le sommet.
Par contre un tableau a un protocole qui permet daccder un
lment quelconque, ce qui est incompatible avec le protocole
des piles.

La smantique de lhritage est telle quune classe drive


doit avoir un protocole compatible, mais aussi une structure
compatible, puisque les champs de la classe de base sont hrits.
Cette contrainte est une source de problmes lorsque lon
dfinit la hirarchie des classes. En effet, le choix de la
Programmer avec des objets 127

hirarchie, qui est initialement guid uniquement par la


compatibilit des protocoles, peut tre invalid plus tard cause
dune incompatibilit de structure. La solution consiste en
gnral crer des classes abstraites dont les classes de structures
incompatibles sont des sous-classes.

Considrons par exemple la classe Polygone, avec comme


mthodes le dessin, la rotation et la translation. La classe
Rectangle, qui reprsente des rectangles dont les cts sont
horizontaux et verticaux, est une candidate pour lhritage, car
son protocole est compatible. Mais lon peut, pour des raisons
defficacit, vouloir reprsenter le rectangle par deux points
diagonaux alors que le polygone ncessite une liste de points.
Lhritage devient impossible, et lon doit introduire une classe
abstraite Forme comme suit :
Forme = classe {
mthodes
procdure Dessiner (f : Fentre);
procdure Rotation (centre : Point; angle : rel);
procdure Translation (v : Vecteur);
}

Polygone = classe Forme { Rectangle = classe Forme {


champs champs
points : Liste [Point]; p1, p2 : Point;
mthodes mthodes
-- idem Forme -- idem Forme
}

Le mme phnomne se reproduit si lon veut dfinir une


classe Carr. Celle-ci devrait en toute logique hriter de
Rectangle, mais si lon veut reprsenter un carr par un point et
une dimension, il faut dfinir une classe Quadrilatre, sous-
classe de Forme, dont Rectangle et Carr sont des sous-classes.
Cela conduit alourdir inutilement la hirarchie dhritage.

Les utilisations de lhritage autres que la spcialisation et


lenrichissement sont gnralement voues sinon lchec, du
moins des solutions de compromis. Lutilisation de lhritage
128 Les langages objets

entre classes de structures compatibles mais de protocoles


incompatibles, comme Tableau et Pile, peut tre acceptable si le
langage permet de masquer la relation dhritage du point de
vue de linclusion de types. Cest le cas par exemple en C++
avec lhritage priv. Dans les autres cas, il vaut mieux y
renoncer, mme si cela alourdit la programmation.

Hritage multiple

Lhritage multiple est source de nombreux problmes. Nous


avons dj voqu les conflits de noms et lhritage rpt. Mais
lhritage multiple pose aussi des problmes dordre
smantique et mthodologique. Selon notre approche de
compatibilit de protocoles, on peut dcider que lhritage
multiple est justifi si la sous-classe a un protocole compatible
avec chacune de ses superclasses. Des conflits de protocoles
peuvent apparatre si une partie du protocole de la sous-classe
est incluse dans les protocoles de plus dune de ses
superclasses : nous avons vu au chapitre 3 lexemple de la
mthode crire dans le cas de la classe TourGM hritant de Tour
et Fentre. Dans ce cas, il faut imprativement redfinir dans la
sous-classe la partie du protocole qui cre des conflits. Si
lhritage multiple est justifi, le protocole redfini devrait faire
appel aux protocoles des superclasses.

Comme lhritage simple, lhritage multiple impose


lhritage de structure des classes parentes. Cet hritage de
structure soulve le problme de lhritage rpt : doit-on
dupliquer les champs hrits dune mme classe par plusieurs
chemins ? Bien que les langages fournissent divers mcanismes
de contrle, comme nous lavons vu, il est plus sain de ne pas
utiliser lhritage multiple dans une telle situation, car les risques
sont grands de rendre la hirarchie des classes inutilisable.
Notons toutefois que lhritage rpt ne provoquera pas de
conflit dhritage de structure si la classe hrite plusieurs fois
est une classe abstraite sans champ : cest la seule situation dans
laquelle lhritage rpt est sans risque.
Programmer avec des objets 129

Dans le cas o lhritage multiple nengendre pas de conflit


de protocole, et si les classes hrites nont pas danctre
commun contenant des champs, alors on peut envisager
lutilisation de lhritage multiple. On obtient alors une classe
agglomre, proche dune classe compose qui aurait un champ
par classe hrite. La diffrence entre classe agglomre et
classe compose est quune instance dune classe agglomre
est dun type compatible avec chacune des classes dont elle
hrite. Chaque classe hrite donne une facette diffrente la
classe agglomre, et les conditions que nous avons imposes
assurent lindpendance de ces facettes. Le polymorphisme
dhritage sur une classe agglomre revient utiliser une
instance de cette classe sous lune de ses facettes.

La similarit entre agglomration et composition nous indique


que, si lon ne souhaite pas mettre en uvre lhritage multiple
pour lune des raisons dcrites ci-dessus, on peut lui substituer
la composition. On ne dispose plus des facettes et de la facilit
de programmation associe, mais on obtient un ensemble de
classes plus facile matriser.

Si la composition peut remplacer lhritage multiple,


lhritage multiple ne doit pas remplacer la composition : ce
nest pas parce quune voiture est constitue dun moteur,
dune carrosserie et de quatre roues quil faut faire hriter la
classe Voiture de la classe Moteur, de la classe Carrosserie et
quatre fois de la classe Roue ! Cest le protocole, et non pas la
structure, qui dtermine lhritage.

6.2 DFINIR LES MTHODES


Nous venons de voir comment les classes et larbre dhritage
sont dfinis. Il est apparu, en particulier, que la notion de
protocole tait cruciale dans la dtermination de lhritage.
Nous allons maintenant fournir des lments afin daider la
dfinition des protocoles, cest--dire des mthodes publiques
des classes. Comme pour les classes, nous allons proposer une
classification des mthodes.
130 Les langages objets

Les mthodes daccs servent obtenir des informations sur le


contenu dun objet, et modifier son tat, sans autre effet de
bord. Laccs peut consister simplement retourner ou affecter
la valeur dun champ, ou bien effectuer un calcul qui utilise
ou modifie la valeur des champs de lobjet. Dans ce dernier cas,
on parlera plutt de mthode de calcul. La plupart des langages
de la famille Smalltalk engendrent automatiquement une
mthode daccs en lecture et une mthode daccs en criture
pour chaque champ. Ceci va lencontre de lencapsulation car
toute classe est alors compltement expose ses clients.

Les mthodes de construction permettent dtablir des


relations entre les objets. Les objets doivent en effet se connatre
afin de pouvoir senvoyer des messages. Pour cela, les objets
stockent des rfrences vers dautres objets, rfrences quil est
ncessaire de maintenir. Dterminer les bonnes mthodes de
construction est une tche dlicate car les relations entre objets
sont souvent complexes.

Par exemple, une fentre doit connatre les objets graphiques


quelle contient, et un objet graphique doit savoir dans quelle
fentre il se trouve. Deux problmes se posent : o mettre la
mthode de construction, et comment tablir le lien, ici
bidirectionnel, entre les objets. La mthode dajout peut tre
dans la classe des fentres ou dans la classe des objets
graphiques. On peut aussi dcider de fournir les deux mthodes.
Dans tous les cas, la mthode de lune des classes devra faire
appel une mthode de lautre classe pour tablir le lien
rciproque, comme dans cet exemple :
procdure Fentre.Ajouter (og : OGraphique) {
-- ajouter og dans la fentre
og.AjoutDans (moi); -- prvenir og
}

On voit ici que les deux classes Fentre et O G r a p h i q u e


entretiennent un lien privilgi : si une autre classe appelle
directement OGraphique.AjoutDans, la relation de rciprocit
entre la fentre et lobjet graphique ne sera pas respecte et le
systme sera dans un tat erron. La seule solution est de faire
Programmer avec des objets 131

en sorte que seule la classe F e n t r e puisse appeler


OGraphique.AjoutDans. Les mcanismes de contrle de
visibilit tels que les amis de C++ et les listes dexportation
dEiffel permettent de raliser cela.

Les mthodes de contrle utilisent le graphe des objets qui


rsulte de lapplication des mthodes de construction pour
raliser un calcul qui met en jeu plusieurs objets. Une mthode
de contrle ne ralise pas de calcul par elle-mme, elle
dtermine les objets comptents et leur retransmet toute ou
partie du calcul. Par exemple, le raffichage dune fentre est
une mthode de contrle qui demande chacun des objets de la
fentre de se redessiner.

De la mme faon que pour les mthodes de construction, les


mthodes de contrle ont souvent besoin de faire appel des
mthodes spcifiques des objets qui ne doivent pas tre
accessibles par dautres clients. Dans lexemple suivant, la
mthode de raffichage dune fentre doit invoquer la mthode
prive I n i t D e s s i n de la fentre afin de mettre en place
lenvironnement ncessaire pour que les objets puissent se
redessiner :
procdure Fentre.Redessiner () {
InitDessin (); -- mettre en place lenvironnement
pour chaque objet graphique o faire
o.Redessiner ();
}
procdure OGraphique.Redessiner () {
-- dessiner lobjet dans sa fentre
}

Les mthodes de dessin des objets graphiques doivent donc


tre visibles seulement par les classes capables de mettre en place
cet environnement avant de les appeler, OGraphique.Redessiner
ne doit donc tre visible que de Fentre.

Les mthodes de classe sont des mthodes globales une


classe. Elles jouent le rle de procdures et fonctions globales,
mais bnficient des mmes rgles de visibilit que les mthodes
132 Les langages objets

normales. Dans les langages qui disposent de mtaclasses, les


mthodes de classes sont dfinies dans celles-ci ; dans les autres
langages, un mcanisme spcifique permet de dclarer des
champs et des mthodes de classe. Les mthodes de classe sont
utilises pour accder aux champs de classe pour contrler le
fonctionnement de lensemble des instances. Nous avons dj
vu une utilisation de mthodes de classe pour numroter les
instances dune classe. Un autre exemple dutilisation est le
contrle, par un champ et des mthodes de classe, du type de
traces mises par les mthodes pour laide la mise au point.

Dfinir la visibilit des mthodes

Les exemples prcdents ont montr limportance de la


visibilit des mthodes pour la scurit de la programmation.
Les langages non typs noffrent pas en gnral de contrle de
visibilit : toute mthode, et mme tout champ (grce aux
mthodes daccs cres automatiquement), est visible de toute
classe. Au contraire, les langages typs offrent diffrents
domaines de visibilit. Cette distinction est rvlatrice des
diffrences dans lutilisation des deux familles de langages.
Avec un langage typ, on souhaite une encapsulation importante
pour assurer une programmation plus sre en effectuant le
maximum de contrles de manire statique. Les langages non
typs, de leur ct, sont souvent utiliss pour le prototypage, et
lon souhaite alors un accs ouvert aux objets afin de faciliter le
dveloppement incrmental du prototype.

Il est souvent dlicat de dterminer le bon domaine de


visibilit de chaque mthode, mme lorsque le contrle de
visibilit est sophistiqu, comme dans Eiffel. En particulier, si
lon dfinit une classe rutilisable, les diffrentes utilisations de
la classe conduiront en gnral modifier linterface, le plus
souvent en rendant visible un plus grand nombre de mthodes.
Les domaines de visibilit dont on a besoin sont les suivants : le
domaine priv la classe, le domaine visible par les sous-classes,
les domaines visibles par des classes privilgies, et le domaine
public toute classe.
Programmer avec des objets 133

Les domaines visibles par des classes privilgies sont les plus
dlicats dfinir, car il faut viter la prolifration des classes
privilgies dune classe donne. Dans un systme bien conu,
les classes fonctionnent par groupes, et chaque classe a pour
classes privilgies les autres classes du groupe. Cela circonscrit
les dpendances entre classes et facilite la rutilisation.

La double distribution

La smantique de lenvoi de message dans les langages


objets consiste dterminer la mthode invoque selon la classe
de lobjet receveur du message. Il arrive frquemment que le
seul receveur ne suffise pas dterminer la bonne mthode, car
celle-ci peut dpendre galement de la classe effective des
paramtres du message. Dans les langages typs, le polymor-
phisme dhritage permet en effet de passer comme paramtres
effectifs des objets dune sous-classe de la classe dclare pour
le paramtre formel. Dans les langages non typs, la classe des
paramtres nentre pas en jeu dans la recherche de mthode.

Dans les deux cas, la technique de la double distribution


( double-dispatching ) permet de rsoudre le problme. Nous
allons lillustrer avec lexemple suivant : deux classes abstraites
Afficheur et OGraphique fournissent des mthodes pour la
reprsentation dobjets graphiques sur des priphriques. La
mthode de dessin dun objet graphique sur un afficheur
dpend la fois de la classe de lafficheur et de celle de lobjet
graphique. Avec les classes Fentre et Imprimante, la double
distribution de la mthode de dessin se ralise comme suit :
Afficheur = classe {
mthodes
procdure Dessiner (o : OGraphique);
}
Fentre = classe Afficheur {
mthodes
procdure Dessiner (o : OGraphique) {
o.AfficherFentre (moi);
}
}
134 Les langages objets

Imprimante = classe Afficheur {


mthodes
procdure Dessiner (o : OGraphique) {
o.AfficherImpr (moi);
}
}

La mthode Dessiner est redfinie dans chaque classe drive,


et appelle une mthode de OGraphique, dont le nom encode la
sous-classe mettrice : cest la premire tape de la double
distribution. La deuxime tape a lieu dans les sous-classes de
OGraphique : chaque mthode daffichage sur un priphrique
donn y est redfinie.

OGraphique = classe {
mthodes
procdure AfficherFentre (aff : Fentre);
procdure AfficherImpr (aff : Imprimante);
}
Rectangle = classe OGraphique {

mthodes
procdure AfficherFentre (aff : Fentre) {
-- dessiner un rectangle dans une fentre
}
procdure AfficherImpr (aff : Imprimante) {
-- dessiner un rectangle sur une imprimante
}
}
Cercle = classe OGraphique {

mthodes
procdure AfficherFentre (aff : Fentre) {
-- dessiner un cercle dans une fentre
}
procdure AfficherImpr (aff : Imprimante) {
-- dessiner un cercle sur une imprimante
}
}
Programmer avec des objets 135

OGraphique Afficheur

AfficheFentre Dessiner
AfficheImpr

Rectangle Cercle Fentre Imprimante

AfficheFentre AfficheFentre Dessiner Dessiner


AfficheImpr AfficheImpr

Figure 29 - Double distribution

La figure 29 illustre le mcanisme : la premire distribution a


lieu dans les sous-classes de Afficheur, et la deuxime dans les
sous-classes de OGraphique. tant donn un objet graphique et
un afficheur, cest finalement lune des mthodes daffichage
des sous-classes de OGraphique qui sera appele.

Si lon rajoute une sous-classe Afficheur, il faut dfinir la


mthode Dessiner dans cette sous-classe ; il faut de plus ajouter
la mthode daffichage correspondante dans OGraphique, et
une implmentation de cette mthode dans chaque sous-classe
de OGraphique. Si lon ajoute une sous-classe OGraphique, il
faut implmenter les mthodes daffichage sur chaque
priphrique dans cette nouvelle classe. On peut noter que
lajout dune nouvelle classe dobjets graphiques peut se faire
sans toucher aux classes dafficheurs, tandis que linverse nest
pas vrai. Ce critre peut aider choisir dans quel sens doit se
faire la double-distribution.

Si lon a n sous-classes de Afficheur et p sous-classes de


OGraphique, il faut implmenter n mthodes dans chaque sous-
classe de OGraphique, soit n*p mthodes. Ceci nest pas
surprenant puisque laffichage dpend du type dafficheur et
du type dobjet graphique. Mais il faut galement implmenter
une mthode de distribution pour chaque sous-classe de
Afficheur, soit n mthodes de plus. De par les services quelle
rend, la double distribution est dun cot acceptable. Notons
136 Les langages objets

galement que, dans un langage typ qui autorise la surcharge


des mthodes (mthodes de mme nom avec des listes de
paramtres diffrentes), les mthodes de distribution peuvent
porter le mme nom (ici se serait Afficher).

6.3 RUTILISER DES CLASSES


La rutilisation de classes est certainement lun des avantages
importants des langages objets. La dfinition de classes
rutilisables nen est pas moins un travail difficile. On se trouve
confront la dfinition de classes rutilisables lorsque lon
conoit une bibliothque, cest--dire un ensemble de classes
fournissant un service particulier. Une telle bibliothque
contient en gnral des classes utiliser telles quelles, et dautres
classes prvues pour tre drives : cest la rutilisation par
hritage. La gnricit offre galement un moyen de
rutilisation puissant, mais comme elle nest pas disponible dans
tous les langages, nous ne lvoquerons pas dans cette partie.

Lorsque lon conoit une bibliothque, on a une ide du type


de rutilisation qui sera employ. Mais dans la pratique, les
classes sont rarement rutilises de la faon que lon avait
imagin : les besoins des utilisateurs ne correspondent pas
exactement au service offert par la bibliothque, ou bien le
mode de rutilisation prvu ne sadapte pas lapplication, ou
bien encore les utilisateurs utilisent mal le mode de rutilisation
prvu. La puissance dune bibliothque de classes sera dautant
plus grande quelle pourra tre utilise de manire non
anticipe. Nous allons voir quelques techniques qui permettent
datteindre cet objectif.

Certaines classes peuvent tre prvues pour tre rutilises


directement, mais la plupart du temps, la rutilisation se fait par
lintermdiaire de lhritage. Cest notamment le cas pour les
classes abstraites. La rutilisation par hritage consiste
redfinir des mthodes de la classe de base, et ajouter de
nouveaux champs et de nouvelles mthodes. Cest la
redfinition qui pose bien sr le plus de problmes. La classe de
Programmer avec des objets 137

base doit dfinir quelles mthodes doivent tre redfinies, celles


qui peuvent tre redfinies, et celles qui ne doivent pas ltre.
Ces trois types de mthodes dpendent du protocole de la classe
de base. Sans cette information, on ne peut pas rutiliser la
classe de base correctement.

Une technique particulirement sre consiste autoriser


seulement la redfinition de mthodes prives, comme le montre
lexemple suivant :

PileAbstraite = classe {
mthodes prives
procdure Ajouter (o : Objet); -- redfinir
procdure Retirer (); -- redfinir
fonction EstVide () : boolen; -- redfinir
fonction Dernier : Objet; -- redfinir
procdure PileVide (); -- redfinir
mthodes -- mthodes publiques
procdure Empiler (o : Objet) {
Ajouter (o);
}
procdure Dpiler () {
si non EstVide () alors Retirer ();
}
fonction Sommet : Objet {
si non EstVide ()
alors retourner Dernier ()
sinon { PileVide (); retourner NUL; }
}
}

Parce quil est trs simple, cet exemple est un peu caricatural.
Il montre nanmoins que, en interdisant la redfinition des
mthodes publiques, on ne peut crer une sous-classe qui ne
respecte pas la smantique dune pile. La mthode PileVide
permet de redfinir la faon de signaler ou de traiter lerreur
qui consiste accder au sommet dune pile vide.
138 Les langages objets

De manire gnrale, le protocole public assure les contrles


de manire respecter la smantique de la classe, tandis que le
protocole priv dfinit les oprations atomiques dfinir dans
chaque sous-classe. Cela nempche pas, le cas chant, de
redfinir une mthode du protocole public dans une sous-classe,
en particulier pour des raisons defficacit.

Classes dpendantes

Lutilisation de classes composes ou agglomres conduit en


gnral des ensembles de classes qui sont prvus pour
fonctionner ensemble. La rutilisation de ces classes doit se faire
en les drivant en parallle, ce qui pose des problmes
spcifiques. Reprenons lexemple des classes Fentre et
OGraphique. Une fentre contient une liste dobjets afficher
et un objet graphique contient la fentre dans laquelle il
saffiche. La drivation parallle a gnralement pour objectif
de dfinir deux nouvelles classes qui, comme leurs classes de
base, doivent fonctionner ensemble.

Par exemple, on cherche dfinir les classes Fentre3D et


OGraphique3D pour laffichage dobjets trois dimensions :

Fentre3D = classe Fentre {


mthodes publiques
procdure Ajouter (o : OGraphique); -- hrite
}

OGraphique3D = classe OGraphique {


mthodes prives
procdure AjoutDans (f : Fentre); -- hrite
}

Une fentre trois dimensions ne peut contenir que des objets


graphiques trois dimensions. Malheureusement, ceci nest pas
reflt par les mthodes hrites : la procdure Fentre.Ajouter
prend un objet graphique quelconque en paramtre, de mme
que la procdure OGraphique.AjoutDans prend une fentre
quelconque en argument.
Programmer avec des objets 139

Dans les langages non typs, il est facile de tester la classe


effective dun objet, comme nous lavons montr au chapitre 4
avec la classe H P i l e . Par contre, il ny a pas de solution
satisfaisante ce problme dans les langages typs. Il faudrait
redfinir la mthode Ajouter avec un paramtre de type
OGraphique3D.

Certains langages, notamment Eiffel, autorisent la redfinition


dune mthode dans une sous-classe avec des paramtres dont
les types sont inclus dans les types des paramtres corres-
pondants dans la classe de base. Malheureusement, le contrle
de type ne peut plus tre ralis statiquement, ce qui fait dEiffel
un langage faiblement typ, comme le montre cet exemple :

U = classe { V = classe U {
procdure g (); procdure h ();
} }
A = classe { B = classe A {
procdure f (p : U) { procdure f (p : V) {
p.g (); p.h ();
} }
} }
a : A; b : B; u: U;
a = b; -- polymorphisme dinclusion
a.f (u); -- la liaison dynamique appelle B.f

Dans cet exemple, la mthode f est redfinie dans la classe B,


avec un paramtre appartenant une sous-classe de celui dclar
pour A.f. Lappel a.f(u) est correct du point de vue du typage
statique. lexcution, a contient un objet de classe B donc, par
liaison dynamique, cest B.f qui sera appele. Malheureusement,
B.f attend un paramtre de type V alors que lon a pass un
paramtre de type U. Pour viter une erreur lexcution, le
compilateur doit engendrer du code pour contrler le type
effectif des objets lexcution.

Dans les langages qui noffrent pas le mcanisme dEiffel, la


seule solution sre consiste fournir une mthode qui permette
de connatre et de tester la classe dun objet. Cela revient
140 Les langages objets

dfinir des objets qui reprsentent des classes, comme les


mtaclasses des langages objets de la famille Smalltalk.

Dans tous les cas, la drivation parallle oblige abandonner


lide dun typage statique, ce qui implique une attention plus
grande lors de la conception du systme pour limiter les
situations qui font intervenir le contrle de types dynamique.

6.4 EXEMPLE : LES TOURS DE HANOI


Nous prsentons dans cette section lexemple complet des
Tours de Hanoi. Nous partons de la classe Tour dfinie dans le
chapitre 3, et nous dfinissons la classe Hanoi qui reprsente le
jeu des Tours de Hanoi.

TourPos = (gauche, centre, droite);


Hanoi = classe {
champs
tours : tableau [TourPos] de Tour;
mthodes
procdure Construire ();
procdure Initialiser (n : entier);
procdure Dplacer (de, vers : TourPos);
procdure Jouer (de, vers, par : TourPos; n : entier);
}

Le type TourPos sert identifier les trois tours. Hanoi est une
classe compose offrant un accs contrl ses composants. Les
corps des mthodes sont les suivants :
procdure Hanoi.Construire () {
tours [gauche] := allouer (Tour);
tours [centre] := allouer (Tour);
tours [droite] := allouer (Tour);
}

procdure Hanoi.Initialiser (n : entier) {


tours [gauche] . Initialiser (n);
tours [centre] . Vider ();
Programmer avec des objets 141

tours [droite] . Vider ();


}

procdure Hanoi.Dplacer (de, vers : TourPos) {


d : entier;
d := tours [de] . Sommet ();
si tours [vers] . PeutEmpiler (d) alors {
tours [de] . Dpiler ();
tours [vers] . Empiler (d);
} sinon
erreur.crire ("Dplacer : coup impossible");
}

procdure Hanoi.Jouer (de, vers, par : TourPos; n : entier) {


si n > 0 alors {
Jouer (de, par, vers, n -1);
Dplacer (de, vers);
sortie.crire (de, " -> ", vers);
Jouer (par, vers, de, n -1);
}
}

Les objets erreur et sortie sont des objets globaux qui


permettent dafficher des messages lcran. allouer permet de
crer un objet dynamiquement (comme le new de Pascal).

On peut utiliser le jeu des Tours de Hanoi comme suit :


hanoi : Hanoi;
hanoi.Construire ();
hanoi.Initialiser (4);
hanoi.Dplacer (gauche, centre);
hanoi.Dplacer (gauche, droite);
hanoi.Dplacer (droite, centre);
-> jouer : coup impossible

La rsolution automatique du jeu se fait de la faon suivante :


hanoi.Initialiser (3); -- revenir la position initiale
hanoi.Jouer ();
gauche -> centre
142 Les langages objets

gauche -> droite


centre -> droite

Les Tours de Hanoi graphiques

Essayons maintenant dutiliser la classe TourG dfinie au


chapitre 3 pour dfinir la classe HanoiG des Tours de Hanoi
graphiques. Il nous suffit de redfinir la mthode Construire
pour allouer des tours graphiques au lieu de tours normales.
Comme les tours graphiques ncessitent une fentre pour
laffichage, nous allons ajouter un champ dans le nouvelle
classe.

HanoiG = classe Hanoi {


champs
f : Fentre;
mthodes prives
procdure ConstruireTour (t : TourPos; x, y : entier);
mthodes
procdure Construire ();
}

procdure HanoiG.ConstruireTour (t : TourPos; x, y : entier) {


tours [t] := allouer (TourG);
tours [t] . Placer (f, x, y);
}

procdure HanoiG.Construire () {
f := allouer (Fentre);
ConstruireTour (gauche,10, 100);
ConstruireTour (centre, 50, 100);
ConstruireTour (droite, 90, 100);
}

La mthode ConstruireTour est une mthode auxiliaire de


Construire. Elle doit donc tre prive.

Lexemple dutilisation de la classe Hanoi sapplique un


objet de la classe HanoiG. Toutefois, les dplacements des
Programmer avec des objets 143

disques ne seront pas visualiss graphiquement. Si lon veut


ajouter cette animation, il faut redfinir la mthode Dplacer.

procdure HanoiG.Dplacer (de, vers : TourPos) {


Hanoi.Dplacer (de, vers);
-- animation

}

Cette solution nest pas satisfaisante car si le dplacement est


invalide, H a n o i . D p l a c e r met un message derreur, et
lanimation ne devrait pas avoir lieu. Le seul moyen de tester la
validit du dplacement dans HanoiG.Dplacer est de rpter le
code de Hanoi.Dplacer, ce qui rend la classe drive HanoiG
dpendante de limplmentation de la classe Hanoi.

Un meilleure solution consiste modifier la classe Hanoi pour


la rendre plus flexible du point de vue de la rutilisation, comme
nous lavons illustr avec la classe PileAbstraite de la section 6.3
ci-dessus. Dfinissons pour cela une mthode prive Bouger,
appele depuis Dplacer lorsque le dplacement est licite :

Hanoi = classe {

mthodes prives

procdure Bouger (d : entier; de, vers : TourPos);
mthodes
procdure Dplacer (de, vers : TourPos);

}

procdure Hanoi.Dplacer (de, vers : TourPos) {


d : entier;
d := tours [de] . Sommet ();
si tours [vers] . OK (d) alors {
tours [de] . Dpiler ();
tours [vers] . Empiler (d);
Bouger (d, de, vers); -- notifier le dplacement
144 Les langages objets

} sinon
erreur.crire ("Dplacer : coup impossible");
}

procdure Hanoi.Bouger (d : entier; de, vers : TourPos) {


-- rien par dfaut
}

La classe HanoiG devient :

HanoiG = classe Hanoi {


champs
f : Fentre;
mthodes prives
procdure ConstruireTour (t : TourPos; x, y : entier);
procdure Bouger (d : entier; de, vers ; TourPos);
mthodes
procdure Construire ();
}

procdure HanoiG.Bouger (d : entier; de, vers : TourPos) {


-- animation du disque d de la tour de vers la tour vers

}

Il nest plus ncessaire de redfinir Dplacer. On a rendu la


classe extensible en dfinissant une mthode prive (ici Bouger)
qui notifie les classes drives dun changement dtat
significatif. Il faut bien reconnatre que, sans la tentative de
drivation, ceci ne serait pas apparu spontanment. Lcriture de
classes rutilisables ncessite donc une connaissance a priori des
contextes de rutilisation.

6.5 CONCLUSION
Ce chapitre nous a montr les possibilits mais aussi les limites
des langages objets. Par rapport aux autres langages, les
langages objets favorisent la modularit et la rutilisation, sans
Programmer avec des objets 145

pour autant rsoudre compltement les problmes lis ces


aspects.

Les exemples de dveloppement dapplications avec un


langage objets ont montr que les classes aident matriser de
gros systmes, condition de les spcifier soigneusement, et de
sadapter au langage en faisant des concessions au modle idal
des objets. En dautres termes, les langages objets sont un outil
puissant et gnral, mais ne sont pas la panace : un problme
ne sest jamais rsolu par la seule vertu des objets.
Bibliographie

Rfrences gnrales
Actes Confrences ECOOP, European Conference on Object-
Oriented Programming. Lecture Notes in Computer Science,
Springer Verlag. vol. 276 (1987), vol. 322 (1988), vol. 512
(1991).
Actes Confrences OOPSLA, Object-Oriented Programming,
Systems, Languages, and Applications. Special Issue SIGPLAN
Notices, ACM. vol. 21, n11 (1986), vol. 22, n12 (1987),
vol. 23, n11 (1988), vol. 24, n10 (1989), vol. 25, n10 (1991).
G. Agha. Actors : a Model of Concurrent Computation in
Distributed Systems. MIT Press, Cambridge (Mass.), 1986.
B.J. Cox. Object-Oriented Programming: an Evolutionary
Approach. Addison-Wesley, Reading (Mass.), 1986.
J. Ferber. Conception et Programmation par Objets. Collection
Techniques de Pointe, Herms, Paris, 1990.
G. Masini, A. Napoli, D. Colnet, D. Lonard, et K. Tombre. Les
Langages Objets. InterEditions, Paris, 1989.
148 Les langages objets

B. Meyer. Conception et Programmation par Objets.


InterEditions, Paris, 1989.
B. Shriver et P. Wegner, editors. Research Directions in Object-
Oriented Programming. MIT Press, Cambridge (Mass.), 1987.
D. Tsichritzis, editor. Centre Universitaire dInformatique,
Universit de Genve. Objects and Things, 1987. Active Object
Environments. 1988. Object Management. 1990. O b j e c t
Composition. 1991.
A. Yonezawa et M. Tokoro, editors. Object-Oriented Concurrent
Programming. MIT Press, Cambridge (Mass.), 1987.

Articles sur des aspects particuliers


Les citations entre crochets font partie des rfrences
gnrales ci-dessus.

G. Agha et C.E. Hewitt. Actors: a Conceptual Foundation for


Concurrent Object-Oriented Programming. In [Shriver et
Wegner, 1987], pp. 49-74.
G. Agha et C.E. Hewitt. Concurrent Programming Using Actors.
In [Yonezawa et Tokoro, 1987], pp. 37-53.
P. Cointe. Implmentation et Interprtation des Langages
Orients Objets. Application aux Langages Smalltalk, Objvlisp
et Formes. Thse de Doctorat dtat, Universit de Paris VII,
LITP 85.55, 1985.
L. Cardelli et P. Wegner. On Understanding Types, Data
Abstraction, and Polymorphism. ACM Computing Surveys,
vol. 17, n4, pp. 471-522, 1985.
W.R. Cook, W.L. Hill, et P.S. Canning. Inheritance is not
Subtyping. Actes Principles of Programming Languages, ACM,
pp. 125-135, 1990.
Bibliographie 149

S. Danforth et C. Tomlinson. Type Theories and Object-


Oriented Programming. ACM Computing Surveys, vol. 20, n1,
pp. 29-72, 1988.
R. Ducourneau et M. Habib. La Multiplicit de lHritage dans
les Langages Objets. Technique et Science Informatique,
vol. 8, n1, pp. 41-62, 1989.
K. Gorlen. An Object-Oriented Class Library for C++ Programs.
Software Practice and Experience, vol. 17, n12, pp. 899-922,
1987.
H. Lieberman. Using Prototypical Objects to Implement Shared
Behavior in Object-Oriented Systems. In [Actes OOPSLA,
1986], pp. 214-223.
B. Meyer. Genericity versus Inheritance. In [Actes OOPSLA,
1986], pp. 391-405.
D. Ungar, C. Chambers, B-W. Chang, et U. Hlzle. Organizing
Programs without Classes. International Journal of Lisp and
Symbolic Computation, vol. 4, n3, 1991.
A. Yonezawa, E. Shibayama, T. Takada, et Y. Honda. Modelling
and Porgramming in an Object-Oriented Concurrent
Programming. In [Yonezawa et Tokoro, 1987], pp. 55-89.

Langages de programmation par objets


Les citations entre crochets font partie des rfrences
gnrales ci-dessus.

Byte Special Issue: the Smalltalk-80 System. Byte, vol. 6, n8,


1981.
L. Cardelli, J. Donahue, L. Glassman, M. Jordan, B. Kalsow, et
G. Nelson. Modula-3 Report (revised). Research Report 52,
DEC Systems Research Center, Palo Alto (Calif.), 1989.
P. Cointe. Metaclasses are First Class: the ObjVLisp Model. In
[Actes OOPSLA, 1987], pp. 156-167.
150 Les langages objets

O.J. Dahl et K. Nygaard. Simula, an Algol-based Simulation


Language. Comm. of the ACM, vol. 9, n9, pp. 671-678, 1966.
L.G. DeMichiel et R.P. Gabriel. The CommonLisp Object
System: an Overview. In [Actes ECOOP, 1987], pp. 201-220.
Eiffel: the Language. Interactive Software Engineering, Inc.,
Goleta (Calif.), 1989.
M. Ellis et B. Stroustrup. The Annotated C++ Reference
Manual. Addison-Wesley, Reading (Mass.), 1990.
A. Goldberg et D. Robson. Smalltalk-80, the Language and its
Implementation. Addison-Wesley, Reading (Mass.), 1983.
S.E. Keene. Object-Oriented Programming in CommonLisp. A
Programmers Guide to CLOS. Addison-Wesley, Reading
(Mass.), 1989.
H. Lieberman. Concurrent Object-Oriented Programming in
Act1. In [Yonezawa et Tokoro, 1987].
S. Lippman. A C++ Primer. Addison-Wesley, Reading (Mass.),
1989.
D. Moon. Object-Oriented Programming with Flavors. In [Actes
OOPSLA, 1986], pp. 1-8.
K. Schmucker. Object-Oriented Programming for the
Macintosh. Hayden Book Company, Hasbrouck Heights, (New
Jersey), 1986.
D. Ungar et R.B. Smith. Self: the Power of Simplicity. In [Actes
OOPSLA, 1987], pp. 227-242.
A. Yonezawa, J-P. Briot, et E. Shibayama. Object-Oriented
Concurrent Programming in ABCL/1. In [Actes OOPSLA,
1986], pp. 258-268.
Index
Ceyx 88
A champ 13, 16, 65, 94
ABCL/1 104, 110 calcul 101
ACT1 104 de classe 86, 127
acteur 11, 104 classe 13, 14, 16, 33, 64, 82, 91,
Ada 2, 4, 7, 15, 25 97, 98, 118
Afficheur 129 abstraite 120, 123, 124, 132
agglomration 125 active 119
Algol 2, 8 agglomre 125, 134
ami 54, 55, 126 amie 54
arbre dhritage 21, 28, 69, atomique 119
120 compose 119, 125, 134
Arc 37 conteneur 58, 119
B de base 21
Bloc 64, 77, 94, 119 dpendante 134
Boolen 71, 74 drive 21
gnrique 58
C primitive 38
C 2, 7, 9, 11, 15 ClasseObjet 83, 85
C++ 4, 8, 9, 31, 35, 47, 50, 51, ClassePile 83, 85
53, 55, 56, 58, 59, 84, clonage 94, 96, 97, 116
96, 120, 124, 126 CLOS 10, 88, 92
cache 73, 103 Clu 15
Carr 123 Collection 120, 122
Cartsien 101 combinaison 24
case 94 CommonLisp 2
152 Les langages objets

communication 110 graphe dhritage 22, 27


comportement exceptionnel 99
composition 24, 125 H
constructeur 56, 59, 84, 96 Hanoi 111, 136
continuation 105 HanoiG 137
Create 56 hritage 14, 64, 69, 98, 121,
132
D dynamique 102
destructeur 57, 59 multiple 22, 27, 44, 90, 124
dlgation 96, 104, 116 priv 54, 124
Dmo 87 rpt 22, 124
dmon 90 simple 18, 22, 39
drivation parallle 134 HPile 71, 86, 134
dictionnaire des mthodes 28,
66, 69, 73 I
domaine de visibilit 53, 128 Imprimante 129
double distribution 129 initialisation 56, 84, 95
instance 13, 14, 16, 64
E instanciation 16, 28, 33, 64, 66,
Eiffel 5, 8, 31, 35, 47, 50, 55, 81, 84, 97
56, 58, 59, 84, 126, Intervalle 78
128, 135 invocation de mthode 17, 33,
encapsulation 6, 15, 17, 52, 128 51, 65, 110, 129
enrichissement 21, 42, 69, 122, itrateur 119, 121, 122
123
Entier 38, 64, 78, 79 J
envoi de message 13, 17, 34, jointure de continuations 109,
62, 104, 110, 116, 113
129 L
F langage
facette 125 objets 13, 111, 140
factorielle 107 typage dynamique 4
Faux 74, 100 typage statique 4
Fentre 42, 44, 124, 129, 134 compil 6, 8, 92
Fentre3D 134 dacteurs 4, 11, 104
Flavors 88, 90 de classes 94, 95, 96, 97,
Forme 123 116
Fortran 2 de prototypes 11, 93, 116
faiblement typ 4, 135
G fortement typ 4, 27
gestion dynamique 59 hybride 11
gnricit 4, 7, 25, 58, 132 impratif 8
GPile 58 interprt 5, 61, 92
Index 153

non typ 5, 28, 61, 92, 103, Modula3 4, 9, 31, 50, 53, 55,
116, 128, 129 59
parallle 3, 104, 116 modularit 6, 7, 116, 140
semi-compil 6, 10, 61 module 6, 15, 16
squentiel 3 moi 36
typ 5, 8, 26, 60, 92, 96,
128, 129, 131, 134 O
Le_Lisp 2, 10, 88 Object Pascal 9
liaison 28 Objective-C 11
dynamique 27, 48, 50, 81, objet 1, 13, 21, 33, 64, 68, 69,
92, 103, 116 83, 91, 94, 111
statique 27, 48 ObjVLisp 10, 88, 90
lien OGraphique 129, 134
dhritage 14, 64, 93, 96 OGraphique3D 134
dinstanciation 14, 64, 65, P
93, 96 parent 96, 102
Lisp 2, 5, 9, 10, 15, 30, 65, 87,
Pascal 2, 4, 7, 13, 15, 25, 59, 78
116 Pile 15, 16, 19, 33, 39, 67, 71,
liste dexportation 55, 126 79, 83, 84, 94, 102
M PileAbstraite 133, 139
mandataire 104 Plasma 104
membre 53 Polaire 101
message 64, 104, 129 Polygone 123
mots cls 62 polymorphisme 24, 28
binaire 62, 72 ad hoc 24, 26, 34, 80
express 110 dhritage 26, 48, 125, 129
unaire 62 dinclusion 25, 26
mta-circularit 10, 30, 84 paramtrique 4, 25, 58
mtaclasse 10, 28, 64, 81, 83, priv 17, 54
90, 127, 135 programmation
mthode 13, 16, 17, 34, 94, 125 fonctionnelle 2, 18, 117
amie 54 imprative 2, 18, 117
daccs 125 logique 2
de calcul 126 modulaire 7
de classe 29, 84, 127 par objets 3, 7, 18, 116, 117
de construction 126 Prolog 3
de contrle 127 protg 54
prive 118 protocole 117, 122, 125, 132
publique 117 protoPile 96, 98
redfinie 20 protoPoint 101
virtuelle 8, 49, 120 protoTour 98
ML 2, 15 prototypage 81, 92, 103, 128
154 Les langages objets

prototype 11, 94 Sommet 37


pseudo-variable sous-classe 21, 64, 71
moi 36 spcialisation 19, 21, 39, 122,
self 72, 95 123
super 72 super 72
public 17, 54 superclasse 21
surcharge 24, 131
Q
Quadrilatre 123 T
table virtuelle 51
R Tableau 67
ramasse-miettes 59, 60 Tour 19, 39, 42, 44, 57, 98,
receveur 17, 34, 62, 105, 129 102, 111, 124, 136
Rectangle 42, 123 TourG 42, 44, 137
redfinition de mthode 20, 26, TourGM 44, 124
41, 69 Tours de Hanoi 18, 98, 111,
rification 30 119, 136
rutilisation 6, 7, 60, 128, 132, typage 4, 8, 27, 28, 30, 49, 81,
134, 139, 140 92, 103, 135
rgles de visibilit 34, 52, 126, type 4, 16, 103
128
V
S variable dinstance 65
Scheme 2 variable de classe 86
self 72 Voiture 125
Self 6, 10, 72, 94, 95 Vrai 74, 100
Simula 1, 4, 8, 31, 50 vue 55
Smalltalk 5, 6, 8, 9, 29, 61, 89,
91, 95, 100, 103, 118,
119, 135

Вам также может понравиться