Considérons le code suivant:
let trois (x : #cell) = x#set(3);; val trois : #cell -> unit = <fun> let bc = new backupCell;; trois(bc);;Le polymorphisme d'inclusion autorise un objet à être vu comme une instance de sa classe éffective, ou comme une instance d'un de ses super-classes. Ainsi, bc de classe backupCell peut être employé comme un objet de classe cell sans danger, et l'appel trois(bc) est correctement typé.
Mais quel est le comportément de cet appel?
En d'autres termes, quel est le comportément de
x#set(3)
lorsque x = bc?
Deux informations sont disponibles. À la compilation,
un typage approximatif de x: il est instance de cell;
lors de l'appel, x = bc où bc est instance
de backupCell.
à la compilation |
![]() |
x : | Type_Instance(cell) |
à l'exécution |
![]() |
x = bc : | Type_Instance(backupCell) |
Dans backupCell, le code de set est re-défini.
Par conséquent, nous avons le choix entre deux
comportéments:
Liason statique |
![]() |
x#set(3) exécute le code
de set dans cell |
Liason tardive |
![]() |
x#set(3) exécute le code
de set dans backupCell |
Dans l'approche orienté objet, on dit que backupCell est le vrai type de bc, et que c'est le vrai type d'un objet qui détermine le choix de la méthode à employer. Ainsi, lors de la compilation de la fonction trois, le choix du code à exécuter pour set, est retardé jusqu'au moment de l'exécution, où un objet efféctif, par exemple bc, est lié au paramètre x. C'est le code de set dans cet objet qui est alors invoqué.
# bc#set 1;; - : unit = () # bc#print;; Actual value: 1 Backup value: 0 - : unit = () # trois(bc);; - : unit = () # bc#print;; Actual value: 3 Backup value: 1 - : unit = ()
On trouve la liason tardive dans tous les langages objet. Il s'agit d'un mécanisme important de l'abstraction dans l'approche objet: un objet doit savoir se comporter de manière autonome, et donc, le contexte n'a pas besoin d'être examiné afin de décider quelle méthode appliquer.