Previous Contents Next

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:

# 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 ``points'' 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: 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 ??).


Previous Contents Next