caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
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


  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;
as well as URLs for NNTP newsgroup(s).