Author: Christian.Queinnec@lip6.fr

## Other Object-oriented Features

### References: `self` and `super`

When defining a method in a class, it may be convenient to be able to invoke a method from a parent class. For this purpose, Objective CAML allows the object itself, as well as (the objects of) the parent class to be named. In the former case, the chosen name is given after the keyword object, and in the latter, after the inheritance declaration.
For example, in order to define the method `to_string` of colored points, it is better to invoke the method `to_string` from the parent class and to extend its behavior with a new method, `get_color`.

    # class colored_point (x,y) c  =
       object (self)
         inherit point (x,y) as super
         val c = c
         method get_color = c
         method to_string () = super#to_string() ^  " [" ^ self#get_color ^ "] "
       end ;;

Arbitrary names may be given to the parent and child class objects, but the names `self` and `this` for the current class and `super` for the parent are conventional. Choosing other names may be useful with multiple inheritance since it makes it easy to differentiate the parents (see page ??).

### Warning

You may not reference a variable of an instance's parent if you declare a new variable with the same name since it masks the former.

### Delayed Binding

With delayed binding the method used when a message is sent is decided at run-time; this is opposed to static binding where the decision is made at compile time. In Objective CAML, delayed binding of methods is used; therefore, the exact piece of code to be executed is determined by the recipient of the message.
The above declaration of class colored_point redefines the method `to_string`. This new definition uses method `get_color` from this class. Now let us define another class colored_point_1, inheriting from colored_point; this new class redefines method `get_color` (testing that the character string is appropriate), but does not redefine `to_string`.

    # class colored_point_1 coord c =
       object
         inherit colored_point coord  c
         val true_colors = ["white"; "black"; "red"; "green"; "blue"; "yellow"]
         method get_color = if List.mem c true_colors then c else "UNKNOWN"
       end ;;

Method `to_string` is the same in both classes of colored points; but two objects from these classes will have a different behavior.

    # let p1 = new colored_point (1,1) "blue as an orange" ;;
    val p1 : colored_point = <obj>
    # p1#to_string();;
    - : string = "( 1, 1) [blue as an orange] "
    # let p2 = new colored_point_1 (1,1) "blue as an orange" ;;
    val p2 : colored_point_1 = <obj>
    # p2#to_string();;
    - : string = "( 1, 1) [UNKNOWN] "

The binding of `get_color` within `to_string` is not fixed when the class colored_point is compiled. The code to be executed when invoking the method `get_color` is determined from the methods associated with instances of classes colored_point and colored_point_1. For an instance of colored_point, sending the message `to_string` causes the execution of `get_color`, defined in class colored_point. On the other hand, sending the same message to an instance of colored_point_1 invokes the method from the parent class, and the latter triggers method `get_color` from the child class, controlling the relevance of the string representing the color.

### Object Representation and Message Dispatch

An object is split in two parts: one may vary, the other is fixed. The varying part contains the instance variables, just as for a record. The fixed part corresponds to a methods table, shared by all instances of the class.
The methods table is a sparse array of functions. Every method name in an application is given a unique id that serves as an index into the methods table. We assume the existence of a machine instruction `GETMETHOD(o,n)`, that takes two parameters: an object `o` and an index `n`. It returns the function associated with this index in the methods table. We write `f_n` for the result of the call `GETMETHOD(o,n)`. Compiling the message send o#m computes the index `n` of the method name `m` and produces the code for applying `GETMETHOD(o,n)` to object `o`. This corresponds to applying function `f_n` to the receiving object `o`. Delayed binding is implemented through a call to `GETMETHOD` at run time.
Sending a message to `self` within a method is also compiled as a search for the index of the message, followed by a call to the function found in the methods table.
In the case of inheritance, since the method name always has the same index, regardless of redefinition, only the entry in new class' methods table is changed for redefinitions. So sending message `to_string` to an instance of class `point` will apply the conversion function of a point, while sending the same message to an instance of `colored_point` will find at the same index the function corresponding to the method which has been redefined to recognize the color field.
Thanks to this index invariance, subtyping (see page ??) is insured to be coherent with respect to the execution. Indeed if a colored point is explicitly constrained to be a point, then upon sending the message `to_string` the method index from class `point` is computed, which coincides with that from class `colored_point`. Searching for the method will be done within the table associated with the receiving instance, i.e. the `colored_point` table.
Although the actual implementation in Objective CAML is different, the principle of dynamic search for the method to be used is still the same.

### Initialization

The class definition keyword initializer is used to specify code to be executed during object construction. An initializer can perform any computation and field access that is legal in a method.

### Syntax

initializer expr

Let us again extend the class `point`, this time by defining a verbose point that will announce its creation.

    # class verbose_point p =
       object(self)
         inherit point p
         initializer
           let xm = string_of_int x and ym = string_of_int y
           in Printf.printf ">> Creation of a point at (%s %s)\n"
                            xm ym ;
              Printf.printf "   , at distance %f from the origin\n"
                            (self#distance()) ;
       end ;;

    # new verbose_point (1,1);;
    >> Creation of a point at (1 1)
       , at distance 1.414214 from the origin
    - : verbose_point = <obj>

An amusing but instructive use of initializers is tracing class inheritance on instance creation. Here is an example:

    # class c1 =
       object
         initializer print_string "Creating an instance of c1\n"
       end ;;

    # class c2 =
       object
         inherit c1
         initializer print_string "Creating an instance of c2\n"
       end ;;

    # new c1 ;;
    Creating an instance of c1
    - : c1 = <obj>
    # new c2 ;;
    Creating an instance of c1
    Creating an instance of c2
    - : c2 = <obj>

Constructing an instance of c2 requires first constructing an instance of the parent class.

### Private Methods

A method may be declared private with the keyword private. It will appear in the interface to the class but not in instances of the class. A private method can only be invoked from other methods; it cannot be sent to an instance of the class. However, private methods are inherited, and therefore can be used in definitions of the hierarchy3.

### Syntax

method private name = expr

Let us extend the class point: we add a method `undo` that revokes the last move. To do this, we must remember the position held before performing a move, so we introduce two new fields, `old_x` and `old_y`, together with their update method. Since we do not want the user to have direct access to this method, we declare it as private. We redefine the methods `moveto` and `rmoveto`, keeping note of the current position before calling the previous methods for performing a move.

    # class point_m1 (x0,y0) =
       object(self)
         inherit point (x0,y0) as super
         val mutable old_x = x0
         val mutable old_y = y0
         method private mem_pos () = old_x <- x ; old_y <- y
         method undo () = x <- old_x; y <- old_y
         method moveto (x1, y1) = self#mem_pos () ; super#moveto (x1, y1)
         method rmoveto (dx, dy) = self#mem_pos () ; super#rmoveto (dx, dy)
     end ;;
    class point_m1 :
      int * int ->
      object
        val mutable old_x : int
        val mutable old_y : int
        val mutable x : int
        val mutable y : int
        method distance : unit -> float
        method get_x : int
        method get_y : int
        method private mem_pos : unit -> unit
        method moveto : int * int -> unit
        method rmoveto : int * int -> unit
        method to_string : unit -> string
        method undo : unit -> unit
      end

We note that method `mem_pos` is preceded by the keyword private in type point_m1. It can be invoked from within method `undo`, but not on another instance. The situation is the same as for instance variables. Even though fields `old_x` and `old_y` appear in the results shown by compilation, that does not imply that they may be handled directly (see page ??).

    # let p = new point_m1 (0, 0) ;;
    val p : point_m1 = <obj>
    # p#mem_pos() ;;
    Characters 0-1:
    This expression has type point_m1
    It has no method mem_pos
    # p#moveto(1, 1) ; p#to_string() ;;
    - : string = "( 1, 1)"
    # p#undo() ; p#to_string() ;;
    - : string = "( 0, 0)"

### Warning

A type constraint may make public a method declared with attribute private.