next up previous
Next: Héritage et polymorphisme paramétrique Up: Types et objets en Previous: Les types ouverts: des

Le polymorphisme des objets en Ocaml

Ocaml est un langage avec inférence de types. Lorsque cela est sûr pour le typage, et qu'il n'y a pas de contraintes de type particulières, le type inféré par le typeur est polymorphe. Nous avons vu au moins deux manières d'interpréter le polymorphisme dans les objets: le polymorphisme d'inclusion, et le polymorphisme paramétrique via l'utilisation de variables de type de rangées. Dans la plupart des langages objets, c'est le premier qui est employé pour typer toutes les constructions objet. En Ocaml, c'est le deuxième qui est utilisé par défaut. Ainsi, si une construction objet est typée en Ocaml, et que l'on ne demande pas explicitement d'utilisert un autre mécanisme de typage, c'est le polymorphisme paramétrique qui est utilisé, soit pour inférer un type polymorphe paramétrique, soit pour l'instancier lors d'un usage polymorphe. Le polymorphisme est synonime de absence totale ou partielle de contraintes de types. Par exemple, la fonction origin plus bas est très générale car elle possède un minimum de contraintes de type.

let origin1 p = p#getx = 0;;
val origin1 : < getx : int; .. > -> bool = <fun>
Cette fonction peut être appliquée à des objets qui possèdent une méthode getx : int mais qui, par exemple, n'ont pas de méthode print
class non_point =
object 
  method getx = 3
  method est_point = false
end

# let np = new non_point;;

# origin1 np;;
- : bool = false
Une deuxième notation permet d'affinner le type de origin avec une contrainte de type sur son argument: il doit être une instance polymorphe de point. En particulier, il doit possèder non seulement la méthode getx : int, mais également au moins toutes les méthodes de la classe point avec des types compatibles. Le type obtenu est bien entendu moins polymorphe:
let origin2 (p : #point) = p#getx = 0;;
val origin2 : #point -> bool = <fun>
Il devient alors impossible d'appliquer la fonction à des objets qui ne possèdent pas, au moins, toutes les méthodes de point.
# origin2(np);;
This expression has type non_point = < est_point : bool; getx : int >
but is here used with type #point = < getx : int; print : unit; .. >
Only the second object type has a method print
 
# let cp = new colorpoint 2 "Rouge";;
# origin2 cp;;
- : bool = false

Lorsque l'on veut contraindre le type de origin à avoir un seul type, celui de point, alors on utilise la notation des types fermés ou monomorphes

let origin3 (p : point) = p#getx = 0;;
val origin3 : point -> bool = <fun>
Il est alors impossible d'appliquer cette fonction à des objets ayant un type différent de point
# origin3 cp;;
This expression has type
  colorpoint = < getcolor : string; getx : int; print : unit >
but is here used with type point = < getx : int; print : unit >
Only the first object type has a method getcolor

# let p = new point 2;;
# origin3 p;;
- : bool = false
Enfin, il est possible en Ocaml de forcer le typeur à utiliser le mécanisme de sous-typage. Dans ce cas, une constrainte explicite de typage est nécessaire.
let origin4 (p) = (p:>point)#getx = 0;;
val origin4 : < getx : int; print : unit; .. > -> bool = <fun>

# origin4 cp;;
- : bool = false

# origin4 p;;
- : bool = false

# origin4 np;;
This expression has type non_point = < est_point : bool; getx : int >
but is here used with type < getx : int; print : unit; .. >
Only the second object type has a method print

Jusqu'ici, le comportément des programmes typés avec polymorphisme paramétrique et avec sous-typage semble équivalent. Dans la pratique, cette équivalence est présente pour la plupart des programmes. Dans la partie dédiée au sous-typage nous examinons quelques différences.


next up previous
Next: Héritage et polymorphisme paramétrique Up: Types et objets en Previous: Les types ouverts: des
Maria-Viginia Aponte
2001-04-10