Author: Christian.Queinnec@lip6.fr

## Classes, Objects, and Methods

The object-oriented extension of Objective CAML is integrated with the functional and imperative kernels of the language, as well as with its type system. Indeed, this last point is unique to the language. Thus we have an object-oriented, statically typed language, with type inference. This extension allows definition of classes and instances, class inheritance (including multiple inheritance), parameterized classes, and abstract classes. Class interfaces are generated from their definition, but may be made more precise through a signature, similarly to what is done for modules.

### Object-Oriented Terminology

We summarize below the main object-oriented programming terms.

class:
  a class describes the contents of the objects that belong to it: it describes an aggregate of data fields (called instance variables), and defines the operations (called methods).
object:
  an object is an element (or instance) of a class; objects have the behaviors of their class. The object is the actual component of programs, while the class specifies how instances are created and how they behave.
method:
  a method is an action which an object is able to perform.
sending a message
  sending a message to an object means asking the object to execute or invoke one of its methods.

### Class Declaration

The simplest syntax for defining a class is as follows. We shall develop this definition throughout this chapter.

### Syntax

class name p1 ...pn =
object
:
instance variables
:
methods
:
end

p1, ..., pn are the parameters for the constructor of the class; they are omitted if the class has no parameters.
An instance variable is declared as follows:

### Syntax

val name = expr
or
val mutable name = expr

When a data field is declared mutable, its value may be modified. Otherwise, the value is always the one that was computed when expr was evaluated during object creation.
Methods are declared as follows:

### Syntax

method name p1 ...pn = expr

Other clauses than val and method can be used in a class declaration: we shall introduce them as needed.

##### Our first class example.

We start with the unavoidable class `point`:

- the data fields `x` and `y` contain the coordinates of the point,
- two methods provide access to the data fields (`get_x` and `get_y`),
- two displacement methods (`moveto`: absolute displacement) and (`rmoveto`: relative displacement),
- one method presents the data as a string (`to_string`),
- one method computes the distance to the point from the origin (`distance`).

    # class point (x_init,y_init) =
       object
         val mutable x = x_init
         val mutable y = y_init
         method get_x = x
         method get_y = y
         method moveto (a,b) =  x <- a ; y <- b
         method rmoveto (dx,dy) =  x <- x + dx ; y <- y + dy
         method to_string () =
             "( " ^ (string_of_int x) ^ ", " ^ (string_of_int y) ^")"
         method distance () = sqrt (float(x*x + y*y))
       end ;;

Note that some methods do not need parameters; this is the case for `get_x` and `get_y`. We usually access instance variables with parameterless methods.
After we declare the class `point`, the system prints the following text:

    class point :
      int * int ->
      object
        val mutable x : int
        val mutable y : int
        method distance : unit -> float
        method get_x : int
        method get_y : int
        method moveto : int * int -> unit
        method rmoveto : int * int -> unit
        method to_string : unit -> string
      end

This text contains two pieces of information. First, the type for objects of the class; this type will be abbreviated as point. The type of an object is the list of names and types of methods in its class. In our example, point is an abbreviation for:

      < distance : unit -> unit; get_x : int; get_y : int;
        moveto : int * int -> unit; rmoveto : int * int -> unit;
        to_string : unit -> unit >

Next, we have a constructor for instances of class `point`, whose type is int*int -> oint. The constructor allows us to construct `point` objects (weŽll just say ```point`s'' to be brief) from the initial values provided as arguments. In this case, we construct a `point` from a pair of integers (meaning the initial position). The constructor `point` is used with the keyword new.
It is possible to define class types:

    # type simple_point = < get_x : int; get_y : int; to_string : unit -> unit > ;;
    type simple_point = < get_x : int; get_y : int; to_string : unit -> unit >

### Note

Type point does not repeat all the informations shown after a class declaration. Instance variables are not shown in the type. Only methods have access to these instance variables.

### Warning

A class declaration is a type declaration. As a consequence, it cannot contain a free type variable.

We will come back to this point later when we deal with type constraints (page ??) and parameterized classes (page ??).

#### A Graphical Notation for Classes

We adapt the UML notation for the syntax of Objective CAML types. Classes are denoted by a rectangle with three parts:

- the top part shows the name of the class,
- the middle part lists the attributes (data fields) of a class instance,
- the bottom part shows the methods of an instance of the class.

Figure 15.1 gives an example of the graphical representation for the class `caml`.

> Figure 15.1: Graphical representation of a class.

Type information for the fields and methods of a class may be added.

### Instance Creation

An object is a value of a class, called an instance of the class. Instances are created with the generic construction primitive `new`, which takes the class and initialization values as arguments.

### Syntax

new name expr1 ...exprn

The following example creates several instances of class point, from various initial values.

    # let p1 = new point (0,0);;
    val p1 : point = <obj>
    # let p2 = new point (3,4);;
    val p2 : point = <obj>
    # let coord = (3,0);;
    val coord : int * int = 3, 0
    # let p3 = new point coord;;
    val p3 : point = <obj>

In Objective CAML, the constructor of a class is unique, but you may define your own specific function `make_point` for point creation:

    # let make_point x = new point (x,x) ;;
    val make_point : int -> point = <fun>
    # make_point 1 ;;
    - : point = <obj>

### Sending a Message

The notation `#` is used to send a message to an object. 2

### Syntax

obj1#name p1 ...pn

The message with method name ``name'' is sent to the object obj. The arguments p1, ..., pn are as expected by the method name. The method must be defined by the class of the object, i.e. visible in the type. The types of arguments must conform to the types of the formal parameters. The following example shows several queries performed on objects from the class `point`.

    # p1#get_x;;
    - : int = 0
    # p2#get_y;;
    - : int = 4
    # p1#to_string();;
    - : string = "( 0, 0)"
    # p2#to_string();;
    - : string = "( 3, 4)"
    # if (p1#distance()) = (p2#distance())
     then print_string ("That's just chance\n")
     else print_string ("We could bet on it\n");;
    We could bet on it
    - : unit = ()

From the type point of view, objects of type point can be used by polymorphic functions of Objective CAML, just as any other value in the language:

    # p1 = p1 ;;
    - : bool = true
    # p1 = p2;;
    - : bool = false
    # let l = p1::[];;
    val l : point list = [<obj>]
    # List.hd l;;
    - : point = <obj>

### Warning

Object equality is defined as physical equality.

We shall clarify this point when we study the subtyping relation (page ??).