
-----------------------------------
wtd
Fri May 06, 2005 12:06 am

O'Caml for OO Programmers
-----------------------------------
O'Caml: A Powerful Option for OO Programming

So far I've mostly talked up O'Caml on its merits as a functional language, but the "O" in the name is shorthand for "Objective" and O'Caml has powerful support for object-oriented programming, and offers some conveniences programmers who work in other OO languages would do well to heed.

Good Habits

Primary among O'Caml's benefits for OO programmers is the fact that all instance variables are private, and methods are public by default.  

Differing from other languages, private methods and instance variables are inherited, but remain private.  As such, there is no "protected" qualifier.  Also handy is that private methods can be made public easily via a type signature.

Inheritance Convenience

Let's consider how we can expose protected methods from a parent class.

class foo 
{
   protected:
      int baz()
      {
         return 42;
      }
};

class bar : public foo
{
   public:
      int baz()
      {
         return foo::baz();
      }
};

Now, a naive O'Caml scenario.

class foo = 
   object (self)
      method private bar = 42
   end 

class bar =
   object (self)
      inherit foo
      method bar = foo#bar
   end

But even better, we can use a type signature for "self".

class foo = 
   object (self)
      method private bar = 42
   end 

class bar =
   object (self : )
      inherit foo
   end

Naming Flexibility

O'Caml's class syntax doesn't lock you into a particular set of names.  Let's say we want "this" as in C++ and Java.

class foo = 
   object (this)
      method private bar = 42
   end 

class bar =
   object (this : )
      inherit foo
   end

Of course, it's also possible to ellide this entirely.  Due to the signature we use in the "bar" class, this isn't possible.

class foo = 
   object
      method private bar = 42
   end 

class bar =
   object (this : )
      inherit foo
   end

We also can't remove these names if we want to access methods from within methods.

class baz = 
   object (self)
      method wooble = 42
      method ninja = self#wooble * 2
   end

The names of inherited classes can be aliased as well.

class qux = 
   object (self)
      inherit baz as super
      method ninja = super#ninja + 1
   end

Other Good Habits: Instance Variables

Let's create a class with an instance variable.  In this case it's a greeter class which contains an instance variable to hold the name of the person to greet.  Methods are available to get a name, and to greet the person.

If a name hasn't been read, raise a No_name exception.

exception No_name

class greeter =
   object (self)
      val name = ""
      method prompt_for_name = print_string "You are? "
      method read_name = name  unit
      method withdraw amount =
         self#deposit (-amount)
      method virtual interest_rate : int
      method private pay_interest =
         self#deposit (int_of_float (float_of_int self#current_balance *. float_of_int self#interest_rate))   
   end

And now savings account can be defined as:

class savings_account = 
   object (self)
      inherit bank_account
      val mutable balance = 0
      method current_balance = balance
      method deposit amount = 
         balance  bool
      method not_equals other = 
         not (self#equals other) 
   end

This abstract class provides for an "equals" method which determines equality between two objects.  The "not_equals" method is defined by default.

Due to the nature of O'Caml's type system, we can't actually refer to a class by name within the class.  We can, however, use a type signature to specify that "self" is the generic type 'a.

class foo =
   object (self)
      inherit equalable
      val mutable a = 42
      method get_a = a
      method set_a new_a = a 