caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Jacques GARRIGUE <garrigue@kurims.kyoto-u.ac.jp>
To: caml-list@inria.fr
Subject: [Caml-list] Re: OCAML Downcasting?
Date: Tue, 21 Sep 2004 17:03:39 +0900 (JST)	[thread overview]
Message-ID: <20040921.170339.118021840.garrigue@kurims.kyoto-u.ac.jp> (raw)
In-Reply-To: <ci9ggm$i6p$1@wolfberry.srv.cs.cmu.edu>

Reposted from comp.lang.ml:

Matthias Kretschmer <mccratch@gmx.net> writes:

> Roy Patrick Tan schrieb:
>
> > I'm trying to learn about ocaml's object-oriented features. It seems
> > like you can coerce an object of one type to a supertype, but not from
> > a supertype to a subtype. But what if I need to recover the original
> > type?
> 
> I am a bit curious why it is that unsafe that it is completely 
> forbidden. Of course type-checks can't be done at elaboration time and 
> have to be postponed to the evaluation time, but most other OO-languages 
> just implement this and if it is impossible, they raise an exception or 
> abort the program. At least something like Oberon's WITH-statement would 
> sometimes be very handy.

There are two important differences between ocaml and other
OO-languages that have downcasting.

- inheritance is not subtyping. The subtyping relation being
  structural, a full fledge typecast would not only require to keep
  type information at runtime, but to embark a large part of the
  compiler to check subtyping. This might also be incredibly slow.

  As a result, downcast is only reasonable when we have both
  inheritance and subtyping. You're suddenly losing a large part of
  the language.

  Worse, even if you have a module interface
     class b :
       object
         inherit a
         ....
       end
  in ocaml this does _not_ mean that b inherits from a, just that it
  has at least a's methods and fields.
  So the semantics of downcast would not allow abstraction.

- classes may have type parameters. Assume a situation like
    class ['a] a = object ... end
  Then we cannot downcast any runtime object to "a", because we don't
  know what is its type parameter. Again, downcast would not mix well
  with other features of the language.

So, while this is somehow unfortunate, there is no downcast in ocaml.

There are various ways to simulate it, but at first this is a bit
confusing for people used to languages with reflection.

> On the other hand, one can overcome this by using sum-types: e.g. You 
> know about button widgets and label widgets. Of course there can be 
> other widgets, so we have 3 different types to distinguish:
> - buttons
> - labels
> - others
> =>
> type mywidget = Button of button_widget
>                | Label of label_widget
>                | Other of widget

This is indeed the standard way to do it, as it mixes best with a
functional programming language.

> In some circumstances this is nice, because you can simply use pattern 
> matching to extract the type you want. On the other hand, when defining 
> this type you have to know excactly what types you want to handle. So it 
> might get very ugly and clumsy.

Phrased this way, this sounds like you have no way to modify the above
type when you need to add a new subtype.
The straightforward thing to do is to use your editor and add a new
case to the above list. Then the compiler will tell you all the places
you need to modify to take this new case into consideration --
something most OO compilers wouldn't bother to tell you: they would
force you to have a default case, which may be relevant or not, and
you would only discover this at runtime.

For the more special cases where you can't modify the original code,
there are still various ways to simulate downcast, from keeping
objects in hashtables to advanced uses of parametric polymorphism.

Just for fun, here is an example of the second approach:

class virtual ['a] widget = object
  method virtual raw : 'a
end

class ['a] button = object (self)
  inherit ['a] widget
  method raw = `Button self
  method press = prerr_endline "pressed"
end

class ['a] label = object (self)
  inherit ['a] widget
  method raw = `Label self
  val mutable text = ""
  method set_text s = text <- s
end

let l = [(new button :> _ widget); (new label :> _ widget)]

let f = function
    `Button b -> b#press
  | `Label l -> l#set_text "Hello" 

let test () =
  List.iter (fun o -> f o#raw) l

Such a programming pattern lets you use downcasting in a refined way,
without any language support. It even avoids the first limitation I
described above (label need not really inherit from widget). But the
fact you must keep 'a polymorphic makes it advanced.

Jacques Garrigue

-------------------
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


       reply	other threads:[~2004-09-21  8:03 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <ci7tcf$qqf$1@wolfberry.srv.cs.cmu.edu>
     [not found] ` <ci9ggm$i6p$1@wolfberry.srv.cs.cmu.edu>
2004-09-21  8:03   ` Jacques GARRIGUE [this message]
2004-09-21  8:43     ` Damien Pous
2004-09-21  9:15       ` Jacques GARRIGUE
2004-09-21  9:29         ` skaller
2004-09-21  9:49           ` Jacques GARRIGUE
2004-09-21  9:34         ` Stefano Zacchiroli
2004-09-21  9:56           ` Jacques GARRIGUE
2004-09-21 19:27     ` Michael Vanier
2004-09-21 21:38       ` Brian Hurt
2004-09-21 22:06         ` Michael Vanier
2004-09-21 22:32           ` Brian Hurt
2004-09-22  1:04           ` skaller
2004-09-21 22:20         ` Marcin 'Qrczak' Kowalczyk
2004-09-22  2:26           ` skaller
2004-09-22  6:31             ` Marcin 'Qrczak' Kowalczyk
2004-09-22  9:03               ` sejourne_kevin
2004-09-22 10:29               ` Richard Jones
2004-09-22 18:39                 ` Brian Hurt
2004-09-22 10:50               ` skaller
2004-09-22 12:03               ` Alain Frisch
2004-09-22 12:50               ` Cláudio Valente
2004-09-22 13:15                 ` Marcin 'Qrczak' Kowalczyk
2004-09-22 15:50                   ` skaller
2004-09-22 18:42               ` Brian Hurt
2004-09-22 18:44                 ` Marcin 'Qrczak' Kowalczyk
2004-09-22 19:18                   ` Brian Hurt
2004-09-22  0:50         ` skaller
2004-09-22  1:30       ` Jacques GARRIGUE
2004-09-22  2:59         ` skaller

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=20040921.170339.118021840.garrigue@kurims.kyoto-u.ac.jp \
    --to=garrigue@kurims.kyoto-u.ac.jp \
    --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;
as well as URLs for NNTP newsgroup(s).