This chapter gives an overview of the object-oriented features of Objective Caml.

The class `point` has one instance variable `x` and two methods
`get_x` and `move`. The initial value of the instance variable is
given here by the class parameter `x_init`. The variable `x` is
declared mutable, so the method `move` can change its value.

# class point x_init = val mutable x = x_init method get_x = x method move d = x <- x + d end;; class point (int) = val mutable x : int method get_x : int method move : int -> unit end

We now create a new point `p`, giving the initialization argument `7`.

# let p = new point 7;; val p : point = <obj>Note that the type of

Let us apply some methods to `p`:

# p#get_x;; - : int = 7 # p#move 3;; - : unit = () # p#get_x;; - : int = 10

The library function `Oo.copy` makes a shallow copy of an object. Its type is
`< .. > as 'a -> 'a` (which is parsed as `(< .. > as 'a) -> 'a`).
The keyword `as` in that type
binds the type variable `'a` to the object type `< .. >`.
Therefore, `Oo.copy` takes an object with any methods (represented by
the ellipsis), and returns an object of the same type. The type of
`Oo.copy` is different from type `< .. > -> < .. >` as each ellipsis
represents a different set of methods. Ellipsis actually behaves as a
type variable.

# let q = Oo.copy p;; val q : point = <obj> # q#move 7; (p#get_x, q#get_x);; - : int * int = 10, 17

Objects can be compared using the generic comparison functions (`=`,
`<`, ...). Two objects are equal if and only if they are physically
equal. In particular, an object and its copy are not equal.

# let q = Oo.copy p;; val q : point = <obj> # p = q, p = p;; - : bool * bool = false, true

We now define a new class `colored_point`. This class inherits from
class `point`. So, it has all the instance variable and all the
methods of `point`, plus a new instance variable `c` and a new method
`color`.

# class colored_point x (c : string) = inherit point x val c = c method color = c end;; class colored_point (int) (string) = val c : string val mutable x : int method color : string method get_x : int method move : int -> unit end # let p' = new colored_point 5 "red";; val p' : colored_point = <obj> # p'#get_x, p'#color;; - : int * string = 5, "red"

A point and a colored point have incompatible types: a point has no
method `color`. However,
the function `get_x` below is a generic function applying method
`get_x` to any object `p` that has this method (and
possibly some others, which are represented by an ellipsis in the
type). Thus, it applies to both points and colored points.

# let get_succ_x p = p#get_x + 1;; val get_succ_x : < get_x : int; .. > -> int = <fun> # get_succ_x p + get_succ_x p';; - : int = 17Methods need not be declared previously, as shown by the example:

# let set_x p = p#set_x;; val set_x : < set_x : 'a; .. > -> 'a = <fun> # let incr p = set_x p (get_succ_x p);; val incr : < get_x : int; set_x : int -> 'a; .. > -> 'a = <fun>

Reference cells can also be implemented as objects. The naive definition fails to typecheck:

# class ref x_init = val mutable x = x_init method get = x method set y = x <- y end;; Characters 5-85: The type variable 'a is not bound in implicit type definition ref = < get : 'a; set : 'a -> unit > It should be captured by a class type parameterThe reason is that at least one of the methods has a polymorphic type (here, the type of the value stored in the reference cell), thus the class should be parametric. A monomorphic instance of the class could be defined by:

# class ref (x_init:int) = val mutable x = x_init method get = x method set y = x <- y end;; class ref (int) = val mutable x : int method get : int method set : int -> unit endA class for polymorphic references must explicitly list the type parameters in its declaration. The type parameters must also be bound somewhere in the class body by a type constraint.

# class 'a ref x_init = val mutable x = (x_init : 'a) method get = x method set y = x <- y end;; class 'a ref ('a) = val mutable x : 'a method get : 'a method set : 'a -> unit end # let r = new ref 1 in r#set 2; (r#get);; - : int = 2The type parameter in the declaration may actually be constrained in the body of the class definition. In the class type, the actual value of the type parameter is displayed in the

# class 'a ref (x_init:'a) = val mutable x = x_init + 1 method get = x method set y = x <- y end;; class 'a ref ('a) = constraint 'a = int val mutable x : int method get : int method set : int -> unit end

Let us consider a more realistic example. We put an additional type
constraint in method `move`, since no free variables must remain uncaptured
by a type parameter.

# class 'a circle (c : 'a) = val mutable center = c method center = center method set_center c = center <- c method move = (center#move : int -> unit) end;; class 'a circle ('a) = constraint 'a = < move : int -> unit; .. > val mutable center : 'a method center : 'a method move : int -> unit method set_center : 'a -> unit end

An alternate definition of `circle`, using a `constraint` clause in
the class definition, is shown below. The type `#point` used below in
the `constraint` clause is an abbreviation produced by the definition
of class `point`. This abbreviation unifies with the type of any
object belonging to a subclass of class `point`. It actually expands to
`< get_x : int; move : int -> unit; .. >`. This leads to the following
alternate definition of `circle`, which has slightly stronger
constraints on its argument, as we now expect `center` to have a
method `get_x`.

# class 'a circle (c : 'a) = constraint 'a = #point val mutable center = c method center = center method set_center c = center <- c method move = center#move end;; class 'a circle ('a) = constraint 'a = #point val mutable center : 'a method center : 'a method move : int -> unit method set_center : 'a -> unit end

The class `colored_circle` is a specialized version of class
`circle` which requires the type of the center to unify with
`#colored_point`, and adds a method `color`.

# class 'a colored_circle c = constraint 'a = #colored_point inherit ('a) circle c method color = center#color end;; class 'a colored_circle ('a) = constraint 'a = #colored_point val mutable center : 'a method center : 'a method color : string method move : int -> unit method set_center : 'a -> unit end

A method can also send messages to the object that invoked the method.
For that, self must be explicitly bound,
here to the variable `s`.

# class printable_point y as s = inherit point y method print = print_int s#get_x end;; class printable_point (int) = val mutable x : int method get_x : int method move : int -> unit method print : unit end # let p = new printable_point 7;; val p : printable_point = <obj> # p#print;; 7- : unit = ()The variable

Multiple inheritance is allowed. Only the last definition of a method
(or of an instance variable) is kept.
Previous definitions of a method can be reused by binding the
related ancestor. Below, `super` is bound to the ancestor
`printable_point`. The name `super` is not actually a variable and
can only be used to select a method as in `super#print`.

# class printable_colored_point y c as self = inherit colored_point y c inherit printable_point y as super method print = print_string "("; super#print; print_string ", "; print_string (self#color); print_string ")" end;; class printable_colored_point (int) (string) = val c : string val mutable x : int method color : string method get_x : int method move : int -> unit method print : unit end # let p' = new printable_colored_point 7 "red";; val p' : printable_colored_point = <obj> # p'#print;; (7, red)- : unit = ()

It is possible to write a version of class `point` without assignments
on the instance variables. The construct `{< ... >}` returns a copy of
``self'' (that is, the current object), possibly changing the value of
some instance variables.

# class functional_point y = val x = y method get_x = x method move d = {< x = x + d >} end;; class functional_point (int) : 'a = val x : int method get_x : int method move : int -> 'a end # let p = new functional_point 7;; val p : functional_point = <obj> # p#get_x;; - : int = 7 # (p#move 3)#get_x;; - : int = 10 # p#get_x;; - : int = 7Note that the type abbreviation

The class `comparable` below is a template for classes with a binary
method `leq` of type `'a -> bool` where the type variable
`'a` is bound to the type of self. Since this class has a method declared
but not defined, it must be flagged virtual and cannot be instantiated
(that is, no object of this class can be created). It still
defines abbreviations. In particular,
`#comparable` expands to `< leq : 'a -> bool; .. > as 'a`.
We see here that the binder `as` also allows to write recursive
types.

# class virtual comparable () : 'a = virtual leq : 'a -> bool end;; class virtual comparable (unit) : 'a = virtual leq : 'a -> bool end

We then define a subclass of `comparable` that wraps integers as
comparable objects. There is a type constraint on the class parameter `x`
as the primitive `<=` is a polymorphic comparison function in
Objective Caml. The `inherit` clause ensures that the type of objects
of this class is an instance of `#comparable`.

# class int_comparable (x : int) = inherit comparable () val x = x method x = x method leq p = x <= p#x end;; class int_comparable (int) : 'a = val x : int method leq : 'a -> bool method x : int end

Objects of class `int_comparable2` below can also modify the integer
they hold. The status of instance variable `x` is changed. It is now
mutable. Note that the type `int_comparable2` is not a subtype of type
`int_comparable`, as the self type appears in contravariant position
in the type of method `leq`.

# class int_comparable2 x = inherit int_comparable x val mutable x method set_x y = x <- y end;; class int_comparable2 (int) : 'a = val mutable x : int method leq : 'a -> bool method set_x : int -> unit method x : int end

The function `min` will return the minimum of any two objects
whose type unifies with `#comparable`. The type of `min` is
not the same as `#comparable -> #comparable -> #comparable`, as
the abbreviation `#comparable` hides a type variable (an
ellipsis). Each occurrence of this abbreviation generates a new
variable.

# let min (x : #comparable) y = if x#leq y then x else y;; val min : (#comparable as 'a) -> 'a -> 'a = <fun>This function can be applied to objects of type

# (min (new int_comparable 7) (new int_comparable 11))#x;; - : int = 7 # (min (new int_comparable2 5) (new int_comparable2 3))#x;; - : int = 3

Protected methods are methods that do not appear in object interfaces. They can only be invoked from other methods of the same object.

# class restricted_point x_init as self = val mutable x = x_init method get_x = x method protected move d = x <- x + d method bump = self#move 1 end;; class restricted_point (int) = val mutable x : int method bump : unit method get_x : int method protected move : int -> unit end # let p = new restricted_point 0;; val p : restricted_point = <obj> # p#move 10;; Characters 0-1: This expression has no method move # p#bump;; - : unit = ()Protected methods are inherited. They can be hidden by signature matching, as described in the next section.

Class interfaces are inferred from class definitions.
They may also be defined directly in interfaces of modules.
For instance, the following is the interface of a module defining
class `restricted_point`.

# module type POINT = sig class restricted_point (int) = val mutable x : int method get_x : int method protected move : int -> unit method bump : unit end end;; module type POINT = sig class restricted_point (int) = val mutable x : int method bump : unit method get_x : int method protected move : int -> unit end end # module Point : POINT = struct class restricted_point x = inherit restricted_point x end end;; module Point : POINTIt is sometime necessary to restrict the interface of classes. Instance variables and protected methods can be hidden by signature matching, as shown below. However, public methods cannot be hidden.

# module type ABSPOINT = sig class restricted_point (int) = method get_x : int method bump : unit end end;; module type ABSPOINT = sig class restricted_point (int) = method bump : unit method get_x : int end end # module Abspoint : ABSPOINT = Point;; module Abspoint : ABSPOINT

Subtyping is never implicit. There are, however, two ways to perform subtyping. The most general construction is fully explicit: both the domain and the codomain of the type coercion must be given.

We have seen that points and colored points have incompatible types.
For instance, they cannot be mixed in the same list. However, a
colored point can be coerced to a point, hiding its `color` method:

# let colored_point_to_point cp = (cp : colored_point :> point);; val colored_point_to_point : colored_point -> point = <fun> # let p = new point 3 and q = new colored_point 4 "blue";; val p : point = <obj> val q : colored_point = <obj> # let l = [p; (colored_point_to_point q)];; val l : point list = [<obj>; <obj>]An object of type

# (p : point :> colored_point);; Characters 0-28: Type point = < get_x : int; move : int -> unit > is not a subtype of type colored_point = < get_x : int; move : int -> unit; color : string >Indeed, backward coercions are unsafe, and should be combined with a type case, possibly raising a runtime error. However, there is not such operation available in the language. Be aware that subtyping and inheritance are not related. Inheritance is a syntactic relation between classes while subtyping is a semantic relation between types. For instance, the class of colored points could have been defined directly, without inheriting from the class of points; the type of colored points would remain unchanged and thus still be a subtype of points. Conversely, the class

# function x -> (x : int_comparable :> comparable);; Characters 14-48: Type int_comparable = < leq : int_comparable -> bool; x : int > is not a subtype of type comparable = < leq : comparable -> bool > Type int_comparable -> bool is not a subtype of type comparable -> bool Type comparable = < leq : comparable -> bool > is not a subtype of type int_comparable = < leq : int_comparable -> bool; x : int >Indeed, an object

The domain of a coercion can usually be omitted. For instance, one can define:

# let to_point cp = (cp :> point);; val to_point : < get_x : int; move : int -> unit; .. > -> point = <fun>In this case, the function

# class virtual c () = virtual m : c end;; class virtual c (unit) = virtual m : c end # class c' () as self = inherit c () method m = (self :> c) method m' = 1 end;; Characters 51-55: This expression cannot be coerced to type c = < m : c >; it has type < m : c; m' : 'a; .. > but is here used with type < m : 'b; m' : 'a; .. > as 'b Type c = < m : c > is not compatible with type 'bThe type of the coercion to type

# function x -> (x :> c);; - : (< m : 'a; .. > as 'a) -> c = <fun>As class

The desired coercion of type `<m : c;..> -> c` can be obtained by using a fully
explicit coercion:

# function x -> (x : #c :> c);; - : #c -> c = <fun>Thus one can define class c' as follows:

# class c' () as self = inherit c () method m = (self : #c :> c) method m' = 1 end;; class c' (unit) = method m : c method m' : int endAn alternative is to define class

# class virtual c () : 'a = virtual m : 'a end;; class virtual c (unit) : 'a = virtual m : 'a endThen, a coercion operator is not even required.

# class c' () as self = inherit c () method m = self method m' = 1 end;; class c' (unit) : 'a = method m : 'a method m' : int endHere, the simple coercion operator

# (new c' () :> c);; - : c = <obj>

Another common problem may occur when one tries to define a coercion to a
class `c` inside the definition of class `c`. The problem is due to the type
abbreviation not being completely defined yet, and so its subtypes are not
clearly known. Then, a coercion `(_ : #c :> c)` is taken to be
the identity function, as in

# function x -> (x :> 'a);; - : 'a -> 'a = <fun>As a consequence, if the coercion is applied to

# class c () as self = method m = (self : #c :> c) end;; Characters 32-48: Type #c = < m : 'a; .. > is not a subtype of type c = < m : 'b; .. >Although declaring the class as

# class closed c () as self = method m = (self : #c :> c) end;; Characters 39-55: Type < m : 'b; .. > as 'a is not a subtype of type c = 'aThis problem can sometimes be avoided by first defining the abbreviation, using a virtual class:

# class virtual c0 () = virtual m : c0 end;; class virtual c0 (unit) = virtual m : c0 end # class c () as self = method m = (self : #c0 :> c0) end;; class c (unit) = method m : c0 endThe class

# class c () as self = inherit c0 () method m = (self : #c0 :> c0) end;; class c (unit) = method m : c0 endOne could think of defining the type abbreviation directly:

# type c1 = <m : c1>;; type c1 = < m : c1 >However, the abbreviation

# class c () as self = method m = (self : <m : c1; ..> as 'a :> c1) end;; class c (unit) = method m : c1 end

Recursive classes can be used to define objects whose types are mutually recursive.

# class window () = val mutable top_widget = (None : widget option) method top_widget = top_widget and widget (w : window) = val window = w method window = window end;; class window (unit) = val mutable top_widget : widget option method top_widget : widget option end class widget (window) = val window : window method window : window endAlthough their types are mutually recursive, the classes

There is sometime an alternative between using modules or classes. Indeed, there are situations when the two approaches are quite similar. For instance, a stack can be straightforwardly implemented as a class:

# exception Empty;; exception Empty # class 'a stack () = val mutable l = ([] : 'a list) method push x = l <- x::l method pop = match l with [] -> raise Empty | a::l' -> l <- l'; a method clear = l <- [] method length = List.length l end;; class 'a stack (unit) = val mutable l : 'a list method clear : unit method length : int method pop : 'a method push : 'a -> unit end

However, writing a method for iterating over a stack is more
problematic. A method `fold` would have type
`('b -> 'a -> 'b) -> 'b -> 'b`. Here `'a` is the parameter of the stack.
The parameter `'b` is not related to the class `'a stack` but to the
argument that will be passed to the method `fold`.
The intuition is that method `fold` should be polymorphic, i.e. of type
`All ('a) ('b -> 'a -> 'b) -> 'b -> 'b`, which is not currently possible.
One possibility would be to make `'b` an extra parameter of class `stack`

# class ('a, 'b) stack2 () = inherit ('a) stack () method fold f (x : 'b) = List.fold_left f x l end;; class ('a, 'b) stack2 (unit) = val mutable l : 'a list method clear : unit method fold : ('b -> 'a -> 'b) -> 'b -> 'b method length : int method pop : 'a method push : 'a -> unit endHowever, method

# let s = new stack2 ();; val s : ('_a, '_b) stack2 = <obj> # s#fold (+) 0;; - : int = 0 # s;; - : (int, int) stack2 = <obj>The best solution would be to make method

Thus, the current solution is to leave the function `fold` outside of the class.

# class 'a stack3 () = inherit ('a) stack () method iter f = List.iter (f : 'a -> unit) l end;; class 'a stack3 (unit) = val mutable l : 'a list method clear : unit method iter : ('a -> unit) -> unit method length : int method pop : 'a method push : 'a -> unit end # let stack_fold (s : 'a #stack3) f x = let accu = ref x in s#iter (fun e -> accu := f !accu e); !accu;; val stack_fold : 'a #stack3 -> ('b -> 'a -> 'b) -> 'b -> 'b = <fun>

Implementing sets leads to another difficulty. Indeed, the method
`union` needs to be able to access the internal representation of
another object of the same class. For that, a `set` class must have
an additional method returning this representation. However, this
representation should not be public. This result is obtained by
making the type of the representation abstract via a module signature
constraint. From outside, the additional method appears like a tag
ensuring that an object belongs to class `set`.

# module type SET = sig type 'a tag class 'a c (unit) : 'b = method is_empty : bool method mem : 'a -> bool method add : 'a -> 'b method union : 'b -> 'b method iter : ('a -> unit) -> unit method tag : 'a tag end end;; module type SET = sig type 'a tag class 'a c (unit) : 'b = method add : 'a -> 'b method is_empty : bool method iter : ('a -> unit) -> unit method mem : 'a -> bool method tag : 'a tag method union : 'b -> 'b end end # module Set : SET = struct let rec merge l1 l2 = match l1 with [] -> l2 | h1 :: t1 -> match l2 with [] -> l1 | h2 :: t2 -> if h1 < h2 then h1 :: merge t1 l2 else if h1 > h2 then h2 :: merge l1 t2 else merge t1 l2 type 'a tag = 'a list class 'a c () : 'b = val repr = ([] : 'a list) method is_empty = (repr = []) method mem x = List.exists ((=) x) repr method add x = {< repr = merge [x] repr >} method union (s : 'b) = {< repr = merge repr s#tag >} method iter (f : 'a -> unit) = List.iter f repr method tag = repr end end;; module Set : SET