From: Benjamin Geer <ben@socialtools.net>
To: caml-list@inria.fr
Subject: [Caml-list] does class polymorphism need to be so complicated?
Date: Wed, 20 Aug 2003 16:42:46 +0100 [thread overview]
Message-ID: <3F4396F6.1010404@socialtools.net> (raw)
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
next reply other threads:[~2003-08-20 15:46 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-08-20 15:42 Benjamin Geer [this message]
2003-08-20 16:05 ` Brian Hurt
2003-08-20 16:19 ` Richard Jones
2003-08-20 16:25 ` Benjamin Geer
2003-08-20 17:09 ` brogoff
2003-08-20 17:25 ` Jacques Carette
2003-08-20 23:34 ` Jacques Garrigue
2003-08-21 13:27 ` Jacques Carette
2003-08-20 18:19 ` Benjamin Geer
2003-08-20 20:39 ` brogoff
2003-08-20 21:04 ` Benjamin Geer
2003-08-21 0:28 ` Jacques Garrigue
2003-08-21 8:17 ` Benjamin Geer
2003-08-21 8:58 ` Jacques Garrigue
2003-08-21 9:38 ` Benjamin Geer
2003-08-21 11:44 ` Remi Vanicat
2003-08-21 13:11 ` Richard Jones
2003-08-21 16:41 ` Remi Vanicat
2003-08-21 18:04 ` brogoff
2003-08-21 20:20 ` Benjamin Geer
2003-08-21 23:35 ` Benjamin Geer
2003-08-22 3:59 ` Jacques Garrigue
2003-08-22 7:12 ` Benjamin Geer
2003-08-21 13:38 ` Benjamin Geer
2003-08-21 0:58 ` brogoff
2003-08-20 23:40 ` Benjamin Geer
2003-08-21 1:29 ` Jacques Garrigue
2003-08-21 9:19 ` Benjamin Geer
2003-08-21 18:44 ` Chris Clearwater
2003-08-20 20:43 ` Issac Trotts
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3F4396F6.1010404@socialtools.net \
--to=ben@socialtools.net \
--cc=caml-list@inria.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox