caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Michael Vanier <mvanier@cs.caltech.edu>
To: caml-list@inria.fr
Subject: [Caml-list] a design problem requiring downcasting? (long)
Date: Thu, 26 Sep 2002 02:01:00 -0700	[thread overview]
Message-ID: <200209260901.g8Q910t03459@orchestra.cs.caltech.edu> (raw)


I've run into a design problem that I think requires downcasting, and I
wanted to see if anyone on the list has any ideas about an alternative
approach, since AFAIK downcasting is impossible in the current ocaml object
system (at least without nasty Obj.magic hacks).  I'll try to simplify the
problem as much as possible, but this is still pretty long.

Here's the problem.  I'm working on the redesign of a large simulation system
originally written in C.  It has all the problems that one always finds in
software written in C: lots of bugs, memory leaks, crashes, etc. etc.  I
would like to re-write this in a safe language, preferably ocaml (since it's
my favorite language).  An alternative might be java, although I think ocaml
would be significantly faster (not to mention more reliable and much more fun
to program in).  C++ would also be a valid choice except that I find that I
can't bear to work in languages without garbage collection anymore, and
anyway, the type discipline of ocaml is a big attraction for me.

It turns out that the design of the core simulator doesn't pose any real
problems.  However, part of the simulation infrastructure is very difficult
to achieve without having a way of downcasting (casting from a supertype to a
subtype).  It can be done, but the design becomes extremely non-modular.  The
issue is that these simulations can contain tens of thousands of simulation
objects which can invoke method calls on each other.  These are actually
binary method calls e.g.

  obj1#my_method obj2

where "obj2" has to be of a specific class type (in actuality, it will be
an interface type).  These method calls are highly dependent on the
specific types of the objects.  If you create the objects like this:

  let obj1 = new class1 in
  let obj2 = new class2 in
  obj1#my_method obj2

then everything works.  However, it is not feasible, when writing a
simulation with this many objects, to keep unique identifiers to each object
that you create.  Therefore, you need some kind of data structure to store
objects after you create them.  For our purposes we can assume that there is
a big master array of these objects.  I see two alternatives for the types of
the array elements.

1) All elements will be instances of subclasses of a base type "base".  The
   array will have the type "base array".

2) The array will be of type "anObject array", where anObject is a variant type
   that can hold the type of any simulation object.

With alternative (1), to do the method call above you would need downcasting
e.g. in pseudo-ocaml:

  let obj1 = array.(0) as class1 in
  let obj2 = array.(1) as class2 in
  obj1#my_method obj2

with the cast raising an exception if it fails.  No problem.  With the
variant type you would have:

  let obj1 = array.(0) in
  let obj2 = array.(1) in
  match (obj1, obj2) with
    (Class1 o1, Class2 o2) -> o1#my_method o2
  | _ -> raise (Failure "bad")

The problem is, every time that a new class is added you have to modify the
variant type.  As if this wasn't bad enough, I envision that "my_method"'s
argument is any class type which implements a particular interface.  So
you'd really have to do this:

  let obj1 = array.(0) in
  let obj2 = array.(1) in
  match obj1 with
    Class1 o1 ->
      match obj2 with
        (* any class that implements the given interface *)
        Class2 o 
      | Class3 o
      | ...
      | ClassN o -> obj1#my_method o
      | _ -> raise (Failure "bad")
  | _ -> raise (Failure "bad")
    
This is getting pretty ugly.  Every time you define a new class which
implements the interface you'd have to modify the above code.  A better
alternative is to call a virtual method on obj1 e.g.

  class class1 =  (* obj1's class *)
    object
      method my_method obj2 =  (* obj2 has the variant type *)
        match obj2 with
          Class2 o 
        | Class3 o
        | ...
        | ClassN o -> obj1#my_method o
        | _ -> raise (Failure "bad")
    end

This is still pretty horrible; for one thing, obj1 is a class type while obj2
is a variant type.  If the array elements are of the variant type, how do you
turn them into the class types?  You could have the array elements be a tuple
of (variant type, superclass type) so you could use whichever form is more
convenient, but that's pretty nasty too.

Compared to this, downcasting looks very sweet.  Actually, I think what I
really want is multimethods ;-)  Is there any way around this that I'm
missing?

Thanks,

Mike




  
-------------------
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:[~2002-09-26 13:33 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-09-26  9:01 Michael Vanier [this message]
2002-09-26 14:32 ` Remi VANICAT
2002-09-26 15:19 ` nadji
2002-09-26 15:27   ` Remi VANICAT
2002-09-26 15:55     ` nadji
2002-09-26 15:53 ` Jeffrey Palmer
2002-09-26 16:35 ` Oleg
2002-09-26 17:47 ` brogoff
2002-09-26 19:14 ` Fred Smith
2002-09-27 17:01   ` Tim Freeman
2002-09-26 22:46 ` Alessandro Baretta
2002-09-27  7:20 ` Francois Pottier
2002-09-27 10:16   ` Michael Vanier
2002-09-29 22:59     ` Alessandro Baretta
2002-09-30  7:09       ` Michael Vanier
2002-09-30  9:54         ` Alessandro Baretta

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=200209260901.g8Q910t03459@orchestra.cs.caltech.edu \
    --to=mvanier@cs.caltech.edu \
    --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).