Nous fermons maintenant la parenthse ``immaginaire'' et revenons à Ocaml tel qu'il fonctionne réellement. Les opérations binaires, à savoir, celles qui prennent deux arguments de même type sont courantes en informatique. Des exemples sont: l'addition, l'égalité, les opérations sur les ensembles (union, intersection), etc. En Programmation OO, ces opérations sont usuellement définies par des méthodes où le premier argument est l'objet receveur du message (et est donc implicite) et le deuxième argument est le seul véritable argument de la méthode. Considérons par exemple, la classe point qui définit une méthode pour comparer deux points par égalité:
class point init = object(self: 'a) val mutable x = init method getx = x method move d = x<-x+d method equal (y:'a) = y#getx = self#getx end;; class colorpoint x (c:string) = object(self: 'a) inherit point x as pointsup val mutable c = c method getcolor = c method setcolor c' = c<-c' method equal (y: 'a) = (y#getcolor = self#getcolor) & pointsup#equal y end;;Examinons les interfaces données pour ces deux classes:
class colorpoint x (c:string) = object(self: 'a) inherit point x as pointsup val mutable c = c method getcolor = c method setcolor c' = c<-c' method equal (y: 'a) = (y#getcolor = self#getcolor) & pointsup#equal end;; class colorpoint : int -> string -> object ('a) val mutable c : string val mutable x : int method equal : 'a -> bool method getcolor : string method getx : int method move : int -> unit method setcolor : string -> unit endet, considérons la fonction suivante:
let breakit (p) = let pt = new point 1 in (p :> point)#equal(pt);; val breakit : < equal : point -> bool; getx : int; move : int -> unit; .. > -> bool
Supposons que colorpoint est un sous-type de point. Alors, on doit pouvoir employer tout point de couleur comme un point. En particulier, la coercion colorpoint :> point doit être possible. Cette coercion est réalisée dans le code de breakit. Ainsi, si colorpoint est un sous-type de point, on doit pouvoir réaliser l'appel breakit(cp) qui à son tour, éffectue cette coercion.
# let cp = new colorpoint 3 "Rouge";; val cp : colorpoint = <obj> breakit(cp);;
![]() |
p#equal(pt) |
![]() |
cp#equal(pt) |
![]() |
(pt#getcolor = cp#getcolor) & pointsup#equal(cp) |
![]() |
erreur (car pt n'a pas de méthode getcolor) |
Si cet appel était executé, une erreur se produit au moment d'évaluer le corps de la fonction: p#equal(pt). En effet, puisque p = cp , alors le code executé pour equal est celui de colorpoint (grâce à la liaison tardive), et alors celui-ci enverra le message getcolor à pt. Or, pt est de type point et ne sait pas comme interpreter ce message et produira donc une erreur. Ainsi, il n'est pas sûr du point de vue du typage d'admettre que colorpoint soit un sous-type de point. Idéalement, un appel à breakit avec un argument effectif de type colorpoint doit être interdit, et ceci par un échec pendant le typage. C'est ce qui se passe en OCaml, qui répond par un long message d'erreur:
# breakit(cp);; ^^ This expression has type colorpoint = < equal : colorpoint -> bool; getcolor : string; getx : int; move : int -> unit; setcolor : string -> unit > but is here used with type < equal : point -> bool; getcolor : string; getx : int; move : int -> unit; setcolor : string -> unit > Type colorpoint = < equal : colorpoint -> bool; getcolor : string; getx : int; move : int -> unit; setcolor : string -> unit > is not compatible with type point = < equal : point -> bool; getx : int; move : int -> unit > Only the first object type has a method getcolor
Ce message nous dit que seul l'argument de type colorpoint
a une méthode getcolor: il nous previent sûr la cause
de l'erreur qui surviendrait si ce code était executé.
Les classes point et colorpoint montrées
plus haut ne sont pas en relation de sous-typage. La raison
est que les types des deux méthodes equal
(dans chacune des deux classes) ne sont pas en relation
de sous-typage. L'explication est assez technique et est donnée
dans la partie suivante.