caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] a design problem requiring downcasting? (long)
@ 2002-09-26  9:01 Michael Vanier
  2002-09-26 14:32 ` Remi VANICAT
                   ` (7 more replies)
  0 siblings, 8 replies; 16+ messages in thread
From: Michael Vanier @ 2002-09-26  9:01 UTC (permalink / raw)
  To: caml-list


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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26  9:01 [Caml-list] a design problem requiring downcasting? (long) Michael Vanier
@ 2002-09-26 14:32 ` Remi VANICAT
  2002-09-26 15:19 ` nadji
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Remi VANICAT @ 2002-09-26 14:32 UTC (permalink / raw)
  To: caml-list

Michael Vanier <mvanier@cs.caltech.edu> writes:

[...]

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

Well, my problem when I read this is the foolowing : How do you know
that you have to call the method my_method of the #2341 object with
the #5232 as argument ?

This information is somewhere (It can't come from nowhere) so There
the type information could be stored (I mean, may be you could put
there not the position of the object in the array, but the object
itself). 

Otherwise there is severall way to make downcast in caml : you could
look to coca-ml
(http://www.pps.jussieu.fr/~emmanuel/Public/Dev/coca-ml/index-en.html)
or to the hweak library (http://aspellfr.free.fr/)


 

-- 
Rémi Vanicat
vanicat@labri.u-bordeaux.fr
http://dept-info.labri.u-bordeaux.fr/~vanicat
-------------------
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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26  9:01 [Caml-list] a design problem requiring downcasting? (long) Michael Vanier
  2002-09-26 14:32 ` Remi VANICAT
@ 2002-09-26 15:19 ` nadji
  2002-09-26 15:27   ` Remi VANICAT
  2002-09-26 15:53 ` Jeffrey Palmer
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: nadji @ 2002-09-26 15:19 UTC (permalink / raw)
  To: Michael Vanier; +Cc: caml-list

Hi,

If I understood your problem, Jacques Garrigue has shown a way
to allow "safe" downcast, that is to say that if you can't downcast you
cleanly get an exeption. You are required to register your class for
all the downcasts you wants, and it will work only for them (i.e. if
you don't register you can't downcast). This is the "memo" class
in the code below.
Following this idea, your simulation manager has to define all the interfaces it
will be using, and the simulations have to register themselves before
beeing used.
Code follows :

(* In simulation infrastructure *)
module Sim = struct
  class ['ct] memo = object
    val h = Hashtbl.create 0
    method add : 'ct -> unit = fun x -> Hashtbl.add h (Obj.repr x) x
    method get : 'a . 'a -> 'ct = fun x -> Hashtbl.find h (Obj.repr x)
  end

  class type base = object
    method simname : string
  end

  class type ct1 = object
    inherit base
    method a : string
  end

  class type ct2 = object
    inherit base
    method b : int
    method bin : 'a. (#ct1 as 'a) -> string
  end

  class type ct3 = object
    inherit base
    method a : string
    method b : int
  end

  let h1 : ct1 memo = new memo
  let h2 : ct2 memo = new memo
  let h3 : ct3 memo = new memo

  let nbsims = ref 0
  let thesims : (int, base) Hashtbl.t = Hashtbl.create 0

  let test a b =
    let obj1 = h1#get a in
    let obj2 = h2#get b in
    obj2#bin obj1
end

(* in sim 1 *)
class class1 = object (self)
  method simname = "sim1"
  method a = "foo"
  method b = 4
  initializer
    Sim.h1#add (self:>Sim.ct1);
    Sim.h3#add (self:>Sim.ct3);
end

(* in sim 2 *)
class class2 = object (self)
  method simname = "sim2"
  method b = 5
  method bin : 'a. (#Sim.ct1 as 'a) -> string =
    fun x -> x#a

  initializer
    Sim.h2#add (self:>Sim.ct2);
end

This is only a suggestion, there are certainly other ways
to achieve what you want.
HTH,
Nadji

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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26 15:19 ` nadji
@ 2002-09-26 15:27   ` Remi VANICAT
  2002-09-26 15:55     ` nadji
  0 siblings, 1 reply; 16+ messages in thread
From: Remi VANICAT @ 2002-09-26 15:27 UTC (permalink / raw)
  To: caml-list

nadji@noos.fr writes:

> Hi,
> 
> If I understood your problem, Jacques Garrigue has shown a way
> to allow "safe" downcast, that is to say that if you can't downcast you
> cleanly get an exeption. You are required to register your class for
> all the downcasts you wants, and it will work only for them (i.e. if
> you don't register you can't downcast). This is the "memo" class
> in the code below.
> Following this idea, your simulation manager has to define all the interfaces it
> will be using, and the simulations have to register themselves before
> beeing used.
> Code follows :
> 

It is what my hweak library is doing. the only difference is that I
use my own Hashtbl with weak pointer (so object that are in my memo
object can be collected by the GC).
-- 
Rémi Vanicat
vanicat@labri.u-bordeaux.fr
http://dept-info.labri.u-bordeaux.fr/~vanicat
-------------------
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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26  9:01 [Caml-list] a design problem requiring downcasting? (long) Michael Vanier
  2002-09-26 14:32 ` Remi VANICAT
  2002-09-26 15:19 ` nadji
@ 2002-09-26 15:53 ` Jeffrey Palmer
  2002-09-26 16:35 ` Oleg
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Jeffrey Palmer @ 2002-09-26 15:53 UTC (permalink / raw)
  To: Michael Vanier, caml-list

On Thursday 26 September 2002 4:01 am, Michael Vanier wrote:
> 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:
>

I'm assuming that each object in the simulation has the ability send a 
"class-specific" message to all of the other objects in the system. (If 
this isn't correct, then please let me know). With this in mind, 
subclassing gets you very little, as most methods aren't applicable (in 
good OO design) at the abstract class level.

I can think of at least three options that can get you what you want 
without downcasting:

1) Use double-dispatch, along the lines of the Visitor pattern. You 
could implement an abstract Visitor class that defaults to no operation 
for most of the classes you'd like to cover, and then subclass 
appropriately to handle the cases that are required for a specific 
method/class combination. I've used this technique extensively (in 
Java), and it's worked well. (You might have to combine this with a 
variant of #2).

2) The problem you're having is because the method "message" isn't smart 
enough to know what it applies to. As they say, abstraction solves most 
problems, so perhaps you could implement a Message class that would be 
passed from object to object (you might not really need objects, at 
that point). You could make some clever use of HOFs and tags to allow 
each object to implement a "does this message apply to me" test, and if 
so it executes it.

3) Since you're already storing all of the objects in an array, why not 
use a subclass-specific storage and pass class-specific messages only 
to that collection. This doesn't handle shared methods so well 
(duplicate storage), but it is an option. You could then implement a 
message dispatcher that knows which collection to use for various 
message types.

Anyway, those are three that I came up with off the top of my head. 
Perhaps I've misunderstood your problem, though. If so, please let me 
know and I'd be happy to try to come up with some more options.

	- jeff

-- 
The river is moving.
The blackbird must be flying.

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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26 15:27   ` Remi VANICAT
@ 2002-09-26 15:55     ` nadji
  0 siblings, 0 replies; 16+ messages in thread
From: nadji @ 2002-09-26 15:55 UTC (permalink / raw)
  Cc: caml-list

Remi VANICAT wrote:

> It is what my hweak library is doing. the only difference is that I
> use my own Hashtbl with weak pointer (so object that are in my memo
> object can be collected by the GC).
>

Yes it's better.
Is there any reason why this is not in the standard library ?
It seems that there is only one functorial interface to weak hash tables,
and they are intended to be used like a set,  while yours is intended to
be used when we want to be "weak" for the key _and_ for the data.
I think it would be useful to have both.
My 2 cents,
nadji

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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26  9:01 [Caml-list] a design problem requiring downcasting? (long) Michael Vanier
                   ` (2 preceding siblings ...)
  2002-09-26 15:53 ` Jeffrey Palmer
@ 2002-09-26 16:35 ` Oleg
  2002-09-26 17:47 ` brogoff
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Oleg @ 2002-09-26 16:35 UTC (permalink / raw)
  To: Michael Vanier, caml-list

On Thursday 26 September 2002 05:01 am, Michael Vanier wrote:
> The problem is, every time that a new class is added you have to modify the
> variant type.

Not with polymorphic variants AFAIK. Have you considered using them?

Cheers,
Oleg
-------------------
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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26  9:01 [Caml-list] a design problem requiring downcasting? (long) Michael Vanier
                   ` (3 preceding siblings ...)
  2002-09-26 16:35 ` Oleg
@ 2002-09-26 17:47 ` brogoff
  2002-09-26 19:14 ` Fred Smith
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: brogoff @ 2002-09-26 17:47 UTC (permalink / raw)
  To: Michael Vanier; +Cc: caml-list

On Thu, 26 Sep 2002, Michael Vanier wrote:
> 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.

I'm not so sure about your specific problem, but when I've wanted my class 
hierarchy to behave more like a sum type I've simply grafted a sum type over the 
set of class types (or virtual classes). Here's a sketch for a composite 

type ('a, 'b) node = Leaf_node of 'a | Hier_node of 'b
and ('a, 'b) instance =
    CellRef of Atom.t * ('a, 'b) node * Geometry.placement
  | CellArrayRef of
      Atom.t * ('a, 'b) node * Geometry.placement * Gdsii.colrow * ipoint * ipoint

class virtual leaf_intf  =
  object
    method virtual full_view : (leaf_intf, hier_intf) node
    (* ... etc... *)
  end 
and virtual hier_intf =
  object
    inherit leaf_intf
    method virtual leaf_view : (leaf_intf, hier_intf) node
    method virtual insts : (leaf_intf, hier_intf) instance list
  end

let as_leaf : (leaf_intf,hier_intf) node -> leaf_intf = function 
    Leaf_node(l) -> (l :> leaf_intf)
  | Hier_node(h) -> (h :> leaf_intf)

let  as_hier : (leaf_intf,hier_intf) node -> hier_intf = function 
  (* ...etc... *)

Obviously, this only works well if you have a fairly small number of 
"abstract base classes", since each one is a type parameter. You don't even need 
to use parametric polymorphism, and you could just declare a type specific to 
this class hierarchy; take a look at 

http://cristal.inria.fr/~remy/cours/appsem/ocaml049.html#toc22

where Didier Remy gives an example using variants and projection functions. 

Also, the weak library mentioned elsewhere looks promising. 

As I get older and lazier, I wonder more if a lot of the OO approaches are 
really easier to grasp. A lot of people are going right for the O before going 
through Caml, and that seems wrong. 

-- Brian


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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26  9:01 [Caml-list] a design problem requiring downcasting? (long) Michael Vanier
                   ` (4 preceding siblings ...)
  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
  7 siblings, 1 reply; 16+ messages in thread
From: Fred Smith @ 2002-09-26 19:14 UTC (permalink / raw)
  To: Michael Vanier, caml-list

Hi Mike,

I have just recently started playing around with classes so am sure that my
solution can be improved.  In fact it may be a duplicate of other solutions
posted on the list although I haven't seen it.  Still it was fun to come up
with so here goes.

The basic idea is to have each class implement a method wrap that returns
self in a variant type that can be dispatched on.  The problem with this
naive approach is that type declarations and class declarations cannot
(AFAIK) be mutually recursive.  Besides it would be best to avoid mutual
recursion if possible.

The solution I propose is one familiar to people with mutually recursive
modules.  Make this wrap method polymorphic and bind the type variable later
on after the definition of the datatype.  I believe this solves the problem
and should be fairly extensible.

The code I used to test my solution is below.  Your array would have
elements of type c_wrapped.

Good luck.

-Fred


class virtual className =
  object
    method virtual className : string
  end
;;

class ['a] c1_raw wrapper =
  object(self)
    inherit className
    method wrap = (wrapper (self :> 'a c1_raw) : 'a)
    method className = "c1"
    method my_method (o : className) = o#className
  end

class ['a] c2_raw wrapper =
  object(self)
    inherit className
    method wrap = (wrapper (self :> 'a c2_raw) :'a)
    method className = "c2"
  end

type classVar = C1 of classVar c1_raw | C2 of classVar c2_raw ;;

class c1 = [classVar]c1_raw (fun o -> C1 o);;
class c2 = [classVar]c2_raw (fun o -> C2 o);;

class type c_wrapped =
    object
      method wrap : classVar
      method className : string
    end
;;

let app o1 o2 =
  match o1#wrap with
    C1 o1' -> o1'#my_method (o2 :> className)
  | _ -> failwith "error"
;;

let o1 = new c1;;
let o2 = new c2;;

app (o1 :> c_wrapped)  (o2 :> c_wrapped)

> -----Original Message-----
> From: owner-caml-list@pauillac.inria.fr
> [mailto:owner-caml-list@pauillac.inria.fr]On Behalf Of Michael Vanier
> Sent: Thursday, September 26, 2002 5:01 AM
> To: caml-list@inria.fr
> Subject: [Caml-list] a design problem requiring downcasting? (long)
>
>
>
> 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

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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26  9:01 [Caml-list] a design problem requiring downcasting? (long) Michael Vanier
                   ` (5 preceding siblings ...)
  2002-09-26 19:14 ` Fred Smith
@ 2002-09-26 22:46 ` Alessandro Baretta
  2002-09-27  7:20 ` Francois Pottier
  7 siblings, 0 replies; 16+ messages in thread
From: Alessandro Baretta @ 2002-09-26 22:46 UTC (permalink / raw)
  To: Michael Vanier; +Cc: caml-list



Michael Vanier wrote:
> 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.
> <long explanation follows>
> 

Scratch... scratch... Hmmm...

I'm not really sure why you would want to use downcasts in 
your problem. I have been taught, as a general rule, that a 
downcast is (usually) a bug in the design and often also a 
bug in the implementation.

Downcasting in O'Caml is only useful when you have classes 
with *different* class types but sharing some common 
ancestor. Then you can keep a reference to the an object of 
the ancestor class and downcast it selectively to recover 
the methods added by inheriting classes. But, then again, if 
your design requires to keep a reference to a generic 
object, you are explicitly throwing out type information: in 
O'Caml upcasts are explicit, so you know *exactly* where you 
are throwing away type information. If you throw out type 
information and subsequently need a downcast to recover it, 
then you are probably working with a wrong abstraction 
somewhere in your analysis.

If I were you, I'd consider using a virtual base class as a 
common ancestor. Such a class would have to define all the 
public methods that might be called on any object. If a 
given method is truly meaningless within a specific class, 
you can always define it as raising a Meaningless_method 
exception, or something similar. But then you'd better make 
sure that your algorithm is correct, or it will die 
miserably with uncaught exceptions.

This is very much like downcasting, but it aids you in 
figuring out exactly what methods are creating the trouble. 
In my last project, I noticed that most typing problems with 
  classes were due to refinements of a base class being 
unified with their ancestor where this was not meaningful. 
It turned out that I could always solve this typing problem 
by isolating newly created objects of the inheriting 
classes, calling what additional methods the iheriting class 
defined in the appropriate order, and upcasting to the base 
class. The new object, thus initialized, could then be 
correctly type-restricted, without ever needing to recover 
the type information thrown away.

This strategy might not necessarily be appicable to your 
case, but I consider it, at least. It might save you a lot 
of hell. Remember: "If God wanted us to downcast, he would 
have given us RTTI."

Alex

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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26  9:01 [Caml-list] a design problem requiring downcasting? (long) Michael Vanier
                   ` (6 preceding siblings ...)
  2002-09-26 22:46 ` Alessandro Baretta
@ 2002-09-27  7:20 ` Francois Pottier
  2002-09-27 10:16   ` Michael Vanier
  7 siblings, 1 reply; 16+ messages in thread
From: Francois Pottier @ 2002-09-27  7:20 UTC (permalink / raw)
  To: Michael Vanier; +Cc: caml-list


Hi,

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

There is something you haven't explained here. How, given the array
indices 0 and 1, do you know that the appropriate classes are class1
and class2? How do map from an index back to the expected class? If
we knew this, perhaps we would able to give better advice.

-- 
François Pottier
Francois.Pottier@inria.fr
http://pauillac.inria.fr/~fpottier/
-------------------
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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-27  7:20 ` Francois Pottier
@ 2002-09-27 10:16   ` Michael Vanier
  2002-09-29 22:59     ` Alessandro Baretta
  0 siblings, 1 reply; 16+ messages in thread
From: Michael Vanier @ 2002-09-27 10:16 UTC (permalink / raw)
  To: Francois.Pottier; +Cc: caml-list

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 3461 bytes --]


First off, thanks very much to all who have responded to my questions.  I
will have to spend the next few days trying to decipher your solutions.  I
anticipate it will be difficult, but interesting ;-)

As to how I know what to do: the short answer is that I just do because I
set up the simulation.  All simulation objects will be subclasses of a base
simulation object class (let's call it "sim_object"), and I want the array
to be able to store any simulation object whatsoever.  Thus, the type of
the array has to be "array of sim_object" (assuming a pure OO approach,
which is not mandatory).  Fine so far.  Now let's go further and assume
that the sim_object class has a method "my_method".  Then given an array
element, standard OO single-dispatch polymorphism would allow you to access
the version of this method for the array element's true class (which is a
subclass of sim_object) when you invoke obj1#my_method.  So if my_method
didn't take any arguments you'd be done.  But here it takes one argument
(obj2), which is also a sim_object or one of its subclasses.  The problem
is, what it does with this argument depends strongly on what subclass it
gets.  Some subclasses it would just reject (throwing an exception).  With
others, it would do some processing.  Therefore, ideally what I'd like is
either:

1) multiple dispatch polymorphism (dispatching on the types of both obj1
   and obj2).  This is the most elegant approach, but almost no languages
   support this (I think because it's very hard to implement efficiently).

2) a way to do a typecase on obj2 to determine which subclass of sim_object
   it is, so I can do the right thing.

Now, the usual way these simulations are set up is that you create obj1,
add it to the array (actually it's not an array but more like a tree
structure, but never mind), then create obj2, add it to the array, and
immediately invoke "obj1#my_method obj2".  The "my_method" call actually
is part of the simulation setup code.  So you know that obj2 is of the
appropriate subclass when you write the code.  In java I believe the
standard approach is to use instanceof and downcasting, but maybe this can
be achieved in a better way using patterns or one of the functional
approaches that have been proposed.

Incidentally, I very much doubt whether I'll ever need more than double
dispatch for this application (no triple+ dispatch, thank you very much).

Thanks again for all the input,

Mike




> Date: Fri, 27 Sep 2002 09:20:23 +0200
> From: Francois Pottier <francois.pottier@inria.fr>
> 
> Hi,
> 
> > 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.
> 
> There is something you haven't explained here. How, given the array
> indices 0 and 1, do you know that the appropriate classes are class1
> and class2? How do map from an index back to the expected class? If
> we knew this, perhaps we would able to give better advice.
> 
> -- 
> François Pottier
> Francois.Pottier@inria.fr
> http://pauillac.inria.fr/~fpottier/
> 
-------------------
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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-26 19:14 ` Fred Smith
@ 2002-09-27 17:01   ` Tim Freeman
  0 siblings, 0 replies; 16+ messages in thread
From: Tim Freeman @ 2002-09-27 17:01 UTC (permalink / raw)
  To: fsmith; +Cc: mvanier, caml-list

Here's another stab at it.  

This is like my previous attempt, except it supports arbitrarily deep
subclassing and multiple inheritance.  This valid issue was raised by
Andreas Rossberg <rossberg@ps.uni-sb.de>.

It's like the try from "Fred Smith" <fsmith@mathworks.com>, except it
avoids polymorphism and having any central place that has to be
modified when you add a class.

This hack has uglier syntax and perhaps slower execution than
equivalent cocaml at
http://www.pps.jussieu.fr/~emmanuel/Public/Dev/coca-ml/index-en.html;
the only advantage of this hack over cocaml are a simpler compilation
environment and avoidance of Obj.magic.

The idea is to represent information about the class of the current
object as a list of exceptions.  There is one exception for each class
the current object can be downcast to.

-- 
Tim Freeman       
tim@fungible.com
GPG public key fingerprint ECDF 46F8 3B80 BB9E 575D  7180 76DF FE00 34B1 5C78 

module type Foo = sig
  exception Wrong_Class
  exception Bad_Downcast

  type 'a downcaster = exn -> 'a
  class downcastable: object
    method downcast: 'a . 'a downcaster -> 'a
  end

  class superclass: object
    inherit downcastable
    method super_meth: string
  end

  val superclass_dc: downcastable -> superclass

  class subclass_1: string -> object
    inherit superclass
    method s: string
  end
                    
  val subclass_1_dc: downcastable -> subclass_1
    
  class subclass_2: int -> object
    inherit superclass
    method i: int
  end
                    
  val subclass_2_dc: downcastable -> subclass_2

  class subsubclass:  object
    inherit subclass_1
    method j: int
  end

  val subsubclass_dc: downcastable -> subsubclass

  class multiclass: object
    inherit subclass_1
    inherit subclass_2
    method sum: int
  end
    
  val multiclass_dc: downcastable -> multiclass
    
  val x: downcastable

end

module Foo: Foo = struct

  exception Wrong_Class
  exception Bad_Downcast

  type 'a downcaster = exn -> 'a
    (** This should throw Wrong_Class if the exception isn't the one we expect,
      otherwise it should grab the argument of the exception. *)

  class downcastable = object (self)
    method private data: exn list = []
    method downcast: 'a . 'a downcaster -> 'a = fun dc ->
      let rec loop l =
        match l with
            [] -> raise Bad_Downcast
          | a :: b ->
              try
                dc a
              with
                  Wrong_Class -> loop b
      in
        loop self#data
  end

  class superclass_impl (makeexn: superclass_impl -> exn) =
  object (self: 'self)
    inherit downcastable
    method private data: exn list = [makeexn (self :> superclass_impl)]
    method super_meth: string = "superclass"
  end
            
  exception Superclass of superclass_impl

  class superclass = superclass_impl (fun sc -> Superclass sc)

  let superclass_dc (dc: downcastable): superclass =
    dc#downcast (function Superclass s -> s
                   | _ -> raise Wrong_Class)
                       
  class subclass_1_impl (s: string) (makeexn: subclass_1_impl -> exn) =
  object (self: 'self)
    inherit superclass as super
    method private data: exn list =
      makeexn (self :> subclass_1_impl) :: super#data
    method s: string = s
  end
    
  exception Subclass_1 of subclass_1_impl

  class subclass_1 (s: string) = subclass_1_impl s (fun sc -> Subclass_1 sc)
    
  let subclass_1_dc (dc: downcastable): subclass_1 =
    dc#downcast (function
                     Subclass_1 s -> s
                   | _ -> raise Wrong_Class)

  class subclass_2_impl (i: int) (makeexn: subclass_2_impl -> exn) =
  object (self: 'self)
    inherit superclass as super
    method private data: exn list =
      makeexn (self :> subclass_2_impl) :: super#data
    method i: int = i
  end
    
  exception Subclass_2 of subclass_2_impl
    
  class subclass_2 (i: int) = subclass_2_impl i (fun sc -> Subclass_2 sc)
    
  let subclass_2_dc (dc: downcastable): subclass_2 =
    dc#downcast (function
                     Subclass_2 s -> s
                   | _ -> raise Wrong_Class)

  class subsubclass_impl (makeexn: subsubclass_impl -> exn) =
  object (self: 'self)
    inherit subclass_1 "subsubclass" as super
    method private data: exn list =
      makeexn (self :> subsubclass_impl) :: super#data
    method j: int = 97
  end

  exception Subsubclass of subsubclass_impl

  class subsubclass = subsubclass_impl (fun sc -> Subsubclass sc)

  let subsubclass_dc (dc: downcastable): subsubclass =
    dc#downcast (function
                     Subsubclass s -> s
                   | _ -> raise Wrong_Class)

  class multiclass_impl (makeexn: multiclass_impl -> exn) =
  object (self: 'self)
    inherit subclass_1 "subsubclass" as super1
    inherit subclass_2 34 as super2
    method private data: exn list =
      makeexn (self :> multiclass_impl) :: (super1#data @ super2#data)
    method sum: int = String.length self#s + self#i
  end

  exception Multiclass of multiclass_impl

  class multiclass = multiclass_impl (fun sc -> Multiclass sc)

  let multiclass_dc (dc: downcastable): multiclass =
    dc#downcast (function
                     Multiclass s -> s
                   | _ -> raise Wrong_Class)

  let _ = Random.self_init ()

  let x: downcastable =
    match Random.bits () mod 5 with
        0 -> (new superclass :> downcastable)
      | 1 -> (new subclass_1 "blort" :> downcastable)
      | 2 -> (new subclass_2 17 :> downcastable)
      | 3 -> (new subsubclass :> downcastable)
      | 4 -> (new multiclass :> downcastable)
      | _ -> failwith "Impossible"  
  let _ =
    try
      Format.printf "Multiclass, sum gives %d.\n@?" (multiclass_dc x)#sum
    with Bad_Downcast -> try
      Format.printf "Subsubclass, j gives %d.\n@?" (subsubclass_dc x)#j
    with Bad_Downcast -> try
      Format.printf "Subclass_2, i gives %d.\n@?" (subclass_2_dc x)#i
    with Bad_Downcast -> try
      Format.printf "Subclass_1, s gives %s.\n@?" (subclass_1_dc x)#s
    with Bad_Downcast -> try
      Format.printf "Superclass; super_meth gives %s.\n@?"
        (superclass_dc x)#super_meth
    with Bad_Downcast ->
      failwith "Downcasts failed"
end
-------------------
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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-27 10:16   ` Michael Vanier
@ 2002-09-29 22:59     ` Alessandro Baretta
  2002-09-30  7:09       ` Michael Vanier
  0 siblings, 1 reply; 16+ messages in thread
From: Alessandro Baretta @ 2002-09-29 22:59 UTC (permalink / raw)
  To: Michael Vanier; +Cc: caml-list



Michael Vanier wrote:

 > 1) multiple dispatch polymorphism (dispatching on the 
types of both obj1
 >    and obj2).  This is the most elegant approach, but 
almost no languages
 >    support this (I think because it's very hard to 
implement efficiently).

Oh, so what you really need is RTTI, not downcasting, 
really. I cannot help you here. I think you need method 
overloading for this one, and I doubt you'll get it soon in 
O'Caml.

 > 2) a way to do a typecase on obj2 to determine which 
subclass of sim_object
 >    it is, so I can do the right thing.

Here's a quick implementation of RTTI in O'Caml which you
can use for your runtime switches

module Sim : sig
   class type sim_obj_t = object ... end
   val new_foo_sim : unit -> [> `Foo_sim of sim_obj_t ]
   val new_bar_sim : unit -> [> `Bar_sim of sim_obj_t ]
end = struct

   class type sim_obj_t = object end

   class virtual sim_obj : sim_obj_t =
   object (self)
   end

   class foo_sim : sim_obj_t =
   object (self)
     inherit sim_obj
   end
   let new_foo_sim () = `Foo_sim (new foo_sim)

   class bar_sim : sim_obj_t =
   object (self)
     inherit sim_obj
   end
   let new_bar_sim () = `Bar_sim (new bar_sim)

end;;

let rtti_algorithm = function
| `Foo_sim x -> "Let's foo!"
| `Bar_sim x -> "Let's bar!"
| _ -> raise Not_found
***

You can place the RTTI dependent code within a method, thus 
obtaining something like double-dispatch polymorphism. Of 
course, you must explicitly code all cases you want your 
code to handle within a single pattern-matching in each 
class implementing your base class type; however, you get 
the plus of not having to keep an explicit roster of all 
your class type flags in one place.

You can also take advantage of the type checker by removing 
the catch-all underscore and letting the compiler signal 
what cases are missing from the pattern matching for it to 
be complete.

I'm curious about this, so I would be glad if you let me 
know what you end up doing.

Alex

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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-29 22:59     ` Alessandro Baretta
@ 2002-09-30  7:09       ` Michael Vanier
  2002-09-30  9:54         ` Alessandro Baretta
  0 siblings, 1 reply; 16+ messages in thread
From: Michael Vanier @ 2002-09-30  7:09 UTC (permalink / raw)
  To: alex; +Cc: caml-list


> Date: Mon, 30 Sep 2002 00:59:29 +0200
> From: Alessandro Baretta <alex@baretta.com>
> 
> Michael Vanier wrote:
> 
>  > 1) multiple dispatch polymorphism (dispatching on the 
> types of both obj1
>  >    and obj2).  This is the most elegant approach, but 
> almost no languages
>  >    support this (I think because it's very hard to 
> implement efficiently).
> 
> Oh, so what you really need is RTTI, not downcasting, 
> really. I cannot help you here. I think you need method 
> overloading for this one, and I doubt you'll get it soon in 
> O'Caml.

I definitely need RTTI.  I'm not sure why you think I need method
overloading.

> 
> I'm curious about this, so I would be glad if you let me 
> know what you end up doing.
> 
> Alex
> 

I'm not sure.  All the approaches I've seen in ocaml seem incredibly heavy
compared with RTTI in java (and/or more brittle).  I'm not sure about your
approach, though (it looks pretty light).  Thanks for the suggestion!

Here is a question for the language designers: is there a technical reason
why RTTI can't be done easily in the ocaml object system?  Or is the lack
of RTTI more of a "moral" issue?  Or is it just due to not enough time to
put in all the features one would like?  I can imagine that the fact that
subtyping is implicit for any class that implements the methods of a
superclass might make RTTI very tricky to implement cleanly in a general
way.  

It's too bad we can't all roll our own object systems for ocaml ;-)

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


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] a design problem requiring downcasting? (long)
  2002-09-30  7:09       ` Michael Vanier
@ 2002-09-30  9:54         ` Alessandro Baretta
  0 siblings, 0 replies; 16+ messages in thread
From: Alessandro Baretta @ 2002-09-30  9:54 UTC (permalink / raw)
  To: Michael Vanier; +Cc: caml-list



Michael Vanier wrote:
> 
> I'm not sure.  All the approaches I've seen in ocaml seem incredibly heavy
> compared with RTTI in java (and/or more brittle).  I'm not sure about your
> approach, though (it looks pretty light).  Thanks for the suggestion!

You are very welcome ;)

> Here is a question for the language designers: is there a technical reason
> why RTTI can't be done easily in the ocaml object system?  Or is the lack
> of RTTI more of a "moral" issue?  Or is it just due to not enough time to
> put in all the features one would like?  I can imagine that the fact that
> subtyping is implicit for any class that implements the methods of a
> superclass might make RTTI very tricky to implement cleanly in a general
> way.  

I don't think there will be any Caml preachers prophesyzing 
your doom for having desired RTTI. I just have a feeling it 
does not fit in cleanly with the type system.

> It's too bad we can't all roll our own object systems for ocaml ;-)
> 
> Mike

Who says you can't? Pick up CamlP4 and write preprocessing 
code adding your favorite flavor of RTTI to your your 
classes. You might very well automate the generation of 
polymorphic-variant-RTTI-tagging object creation 
functions--my flavor of RTTI--or any other flavor you like 
best. One might even come up with a syntax extension 
supporting some form of double-dispatch polymorphism. But, 
to my great dishonor, I'm still not a CamlP4 guru, so I'll 
leave this to others.

Alex

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


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2002-09-30 10:32 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-26  9:01 [Caml-list] a design problem requiring downcasting? (long) Michael Vanier
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

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