Rappelons le code des classes cell et backupCell
class cell = object(self) val mutable cont = 0 method get = cont method set n = cont <- n method double = self#set (cont*2) method print = print_int self#get end;; class backupCell = object inherit cell as super val mutable backup = 0 method set n = backup <- cont; super#set n; method print = print_string "Actual value: "; super#print; print_newline(); print_string "Backup value: "; print_int backup; print_newline() method restore = cont <- backup end;; let c = new cell;; let bc = new backupCell;; bc#set(1);; - : unit = () bc#print;; Actual value: 1 Backup value: 0 - : unit = () bc#double;;
Quel est le comportément de l'invocation bc#double
?
bc#double => invocation de la methode double de cell => self#set(cont*2) => invocation de quelle methode set?
L'objet référencé par self est l'objet courant. Mais qui
est cet objet là? Clairement, au moment
où le code self#set(cont*2)
est écrit, il n'y a pas d'objet encore
lié à self. Cette liaison ne peut être établie que de
manière dynamique. Dans notre cas, l'objet courant (le dernier
activé par un envoi de messages) est
bc. Nous obtenons
bc#double => self#set(cont*2) avec self = bc => bc#set(cont*2) => backup <- cont; super#set(cont*2) => backup <- cont; cont <- cont*2 => backup <- 1; cont <- 2
Ainsi, lors de la compilation de
self#set(cont*2)
, le choix du code à invoquer pour la méthode
set est retardé jusqu'au moment de l'exécution,
quand il est possible d'établir dynamiquement
une liaison pour self.
C'est à ce moment-là que le code pour set est selectionné:
il s'agit de celui dans l'objet lié à
self. Dans notre cas, il s'agit du code de set dans
bc.
Dans notre exemple, il est important de comprendre que le code exécuté, n'est pas celui qui correspond à une liaison statique pour la méthode set. La méthode double invoquée est celle héritée de cell. Or, double invoque à son tour sa méthode soeur set. Dans la mesure où cette demande apparaît textuellement dans cell, on peut s'interroger: s'agit-il de set dans cell ou dans backupCell? Le schéma suivant montre la pertinence de la question:
class cell = ... method set n = ... method double = self#set (cont*2) (* quel methode set ici ? *) ... end class backupCell = ... inherit cell method set n = (* methode redefinie *) ... end
Comme dans le cas précédent, nous avons deux choix possibles
Liason statique |
![]() |
self#set(cont*2)
exécute le code
dans cell |
Liason tardive |
![]() |
self#set(cont*2)
exécute le code
dans backupCell |
Et comme dans le cas précédent, le choix de la méthode est retardé jusqu'à l'exécution. Cette fois, c'est grâce à l'invocation de set via self, et au mécanisme de liaison dynamique pour celui-ci, que le choix de code pour set devient retardé.