Version française
Home     About     Download     Resources     Contact us    
Browse thread
[Caml-list] does class polymorphism need to be so complicated?
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Benjamin Geer <ben@s...>
Subject: [Caml-list] does class polymorphism need to be so complicated?
I'm looking for a convenient way to use a derived class anywhere its 
base class can be used.  There seem to be two ways to do this, but 
neither of them is convenient.

For example, suppose I have the following examples (borrowed from the 
O'Reilly Caml book):

class virtual printable () =
    object (self)
      method virtual to_string : unit -> string
      method print () = print_string (self#to_string())
    end ;;

class point (x_init, y_init) =
   object
     inherit printable ()
     val mutable x = x_init
     val mutable y = y_init
     method get_x = x
     method get_y = y
     method to_string () =
       "( " ^ (string_of_int x) ^ ", " ^ (string_of_int y) ^")"
   end ;;

I want to make a class 'printer', which prints the string representation 
of any 'printable'.  It seems that I have two options:

1. Write 'printer' like this:

class printer =
   object
     method print (obj : printable) = obj#print()
   end ;;

And use it like this:

let p = new point (1, 2) ;;
let pr = new printer ;;
pr#print (p :> printable) ;;

It is cumbersome to have to write the coercion, and it seems strange to 
have to do so in an object-oriented language; why can't Caml recognise 
that a 'point' is a 'printable', and do the coercion automatically?

Moreover, it introduces a potential maintenance problem.  Suppose that, 
after writing the application, I decide to to move the printing logic 
out of 'printable', and into the 'printer' class.  I refactor the 
classes like this:

class virtual stringable () =
    object
      method virtual to_string : unit -> string
    end ;;

class virtual printable () =
    object (self)
      inherit stringable ()
      method print () = print_string (self#to_string())
    end ;;

class printer =
   object
     method print (obj : stringable) = print_string (obj#to_string())
   end ;;

But now I have to change all the coercions from (p :> printable) to (p 
:> stringable).  If it had been legal to write:

let p = new point (1, 2) ;;
let pr = new printer ;;
pr#print p ;;

there would be nothing more to change; all the calls to 'pr#print' would 
still work.

2. The second option is to write 'printer' like this:

class printer =
   object
     method print : 'a. (#printable as 'a) -> unit =
       fun obj -> obj#print()
   end ;;

This syntax is horribly awkward.  It would be very unpleasant to have to 
write (or read) a lot of methods in this style.  Moreover, it seems 
strange to have to do this, because I can write a function like this:

let print (obj : #printable) = obj#print() ;;

Or even:

let print obj = obj#print() ;;

So why can't I write:

class printer =
   object
     method (obj : #printable) = obj#print()
   end ;;

Or even:

class printer =
   object
     method obj = obj#print()
   end ;;

Why isn't a method just like a function in this respect?

Of course, I could write 'printer' as a function instead of a class. 
But this would lead to an approach in which objects are manipulated only 
by functions, and never by other objects.  If that were really the only 
convenient way to use classes in Caml, it would be difficult to say that 
Caml supported object-oriented programming.

So my questions are:

Does it really need to be this complicated?  Could the language be 
improved so that either (1) explicit coercions to a base class were not 
needed or (b) methods could use types the way functions do?

Is there a more convenient approach that I've missed?  What do people 
generally do in order to get round this problem, when using classes in Caml?

Ben

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners