From: tim@fungible.com (Tim Freeman)
To: fsmith@mathworks.com
Cc: mvanier@cs.caltech.edu, caml-list@inria.fr
Subject: Re: [Caml-list] a design problem requiring downcasting? (long)
Date: Fri, 27 Sep 2002 10:01:26 -0700 [thread overview]
Message-ID: <20020927172204.079137FEE@lobus.fungible.com> (raw)
In-Reply-To: <IIEMJEMIMDMLIIPHPOBLGEKKCAAA.fsmith@mathworks.com>
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
next prev parent reply other threads:[~2002-09-27 17:22 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-09-26 9:01 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 [this message]
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=20020927172204.079137FEE@lobus.fungible.com \
--to=tim@fungible.com \
--cc=caml-list@inria.fr \
--cc=fsmith@mathworks.com \
--cc=mvanier@cs.caltech.edu \
/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