caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Why can't immediate objects be extended?
@ 2008-07-12 14:12 Richard Jones
  2008-07-12 14:26 ` [Caml-list] " Richard Jones
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Richard Jones @ 2008-07-12 14:12 UTC (permalink / raw)
  To: caml-list


I'm wondering if there's a reason why one cannot inherit from
immediate objects? (See description at:
http://caml.inria.fr/pub/docs/manual-ocaml/manual005.html#ss:immediate-objects)
Is it just a syntax problem because the 'inherit' keyword currently
needs to take a class type, or is there a deeper reason?

This is the code I'd like to write (non-working, obviously):

  type 'a tree = Leaf of string | Node of 'a tree * 'a * 'a tree
  
  let none = object end
  
  let tree = Node (Leaf "1", none, Leaf "2")
  
  let rec string_of_tree = function
    | Leaf str -> str
    | Node (left, _, right) ->
        "(" ^ string_of_tree left ^ "," ^ string_of_tree right ^ ")"
  
  let rec annotate = function
    | (Leaf _ as t) -> t
    | (Node (left, parent_obj, right) as t) ->
        let obj = object
  	  inherit (typeof parent_obj)
  	  method str = string_of_tree t
        end in
        Node (annotate left, obj, annotate right)

  let tree = annotate tree

The problematic function is 'annotate'.  I believe I want annotate to
have a type along these lines (again, this is not precisely OCaml code
because I've used alpha to stand for '..'):

  val annotate : < 'a > tree -> < str : string; 'a > tree

Rich.

-- 
Richard Jones
Red Hat


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

* Re: [Caml-list] Why can't immediate objects be extended?
  2008-07-12 14:12 Why can't immediate objects be extended? Richard Jones
@ 2008-07-12 14:26 ` Richard Jones
  2008-07-14  1:47 ` Peng Zang
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Richard Jones @ 2008-07-12 14:26 UTC (permalink / raw)
  To: caml-list

On Sat, Jul 12, 2008 at 03:12:00PM +0100, Richard Jones wrote:
>         let obj = object
>   	  inherit (typeof parent_obj)
>   	  method str = string_of_tree t
>         end in
>         Node (annotate left, obj, annotate right)

Further exploration reveals I can write this, which is _almost_ what I
want:

  let obj = object
    inherit object method parent = parent_obj end
    method str = string_of_tree t
   end in ...

except the indirection through a parent method is not helpful for what
I'm trying to achieve (an extensible static type that doesn't depend
on the order in which the type is extended).

The types produced by this are:

  val annotate : 'a tree -> < parent : 'a; str : string > tree = <fun>

  val tree : < parent : <  >; str : string > tree = (* ... *)

Rich.

-- 
Richard Jones
Red Hat


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

* Re: [Caml-list] Why can't immediate objects be extended?
  2008-07-12 14:12 Why can't immediate objects be extended? Richard Jones
  2008-07-12 14:26 ` [Caml-list] " Richard Jones
@ 2008-07-14  1:47 ` Peng Zang
  2008-07-14 14:38 ` Keiko Nakata
  2008-07-16  1:43 ` Jacques Garrigue
  3 siblings, 0 replies; 5+ messages in thread
From: Peng Zang @ 2008-07-14  1:47 UTC (permalink / raw)
  To: caml-list; +Cc: Richard Jones, caml-list

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Saturday 12 July 2008 10:12:00 am Richard Jones wrote:
> I'm wondering if there's a reason why one cannot inherit from
> immediate objects? (See description at:
> http://caml.inria.fr/pub/docs/manual-ocaml/manual005.html#ss:immediate-obje
>cts) Is it just a syntax problem because the 'inherit' keyword currently
> needs to take a class type, or is there a deeper reason?

I have no idea, however, using some black magic we can accomplish exactly 
this:

- ----------- snip of temp.ml -------------
(** ported from hash.c **)
let caml_hash_variant name = 
  let acc = ref 0 in
  let len = String.length name in
    for i = 0 to len - 1 do
      acc := (223 * !acc + Char.code (String.get name i)) land 0x7FFFFFFF;
    done;
    !acc
;;

(** the return type is needs casting **)
let addmethod obj methodname methodfun = 
  let methodsuite = Obj.field obj 0 in
  let newms = 
    let nummethods : int = Obj.magic (Obj.field methodsuite 0) in
    let size = Obj.size methodsuite in
    let arr = Array.create (size+2) 0 in
      arr.(0) <- nummethods + 1;
      for i = 1 to size - 1 do
        arr.(i) <- Obj.magic (Obj.field methodsuite i);
      done;
      arr.(size) <- methodfun;
      arr.(size+1) <- caml_hash_variant methodname;
      arr in
  let obj' = Obj.dup obj in
    Obj.set_field obj' 0 (Obj.magic newms);
    obj'
;;
let addmethod = Obj.magic addmethod
let addmethod : (< .. > as 'a) -> string -> ('a -> 'b) -> < .. > = addmethod;;

    

let foo = object method foo = "foo" end;;
let foobar : <foo:string; bar:string> = addmethod foo "bar" (fun _ -> "bar");;

foo#foo;;
foobar#foo;;
foobar#bar;;
- ----------- end snip ----------


        Objective Caml version 3.09.3
# #use "temp.ml";;
val caml_hash_variant : string -> int = <fun>
val addmethod : Obj.t -> string -> int -> Obj.t = <fun>
val addmethod : 'a = <poly>
val addmethod : (< .. > as 'a) -> string -> ('a -> 'b) -> < .. > = <fun>
val foo : < foo : string > = <obj>
val foobar : < bar : string; foo : string > = <obj>
- - : string = "foo"
- - : string = "foo"
- - : string = "bar"
# 


Not pretty, but it works,


Peng
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.7 (GNU/Linux)

iD8DBQFIerBLfIRcEFL/JewRAnTpAJ9LdD09DsVvgJHemCf3ROzGqH+dQwCfRAoX
7sOvInXyvq8jDfF+ucZhzic=
=V3Ki
-----END PGP SIGNATURE-----


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

* Re: [Caml-list] Why can't immediate objects be extended?
  2008-07-12 14:12 Why can't immediate objects be extended? Richard Jones
  2008-07-12 14:26 ` [Caml-list] " Richard Jones
  2008-07-14  1:47 ` Peng Zang
@ 2008-07-14 14:38 ` Keiko Nakata
  2008-07-16  1:43 ` Jacques Garrigue
  3 siblings, 0 replies; 5+ messages in thread
From: Keiko Nakata @ 2008-07-14 14:38 UTC (permalink / raw)
  To: rich; +Cc: caml-list

Hello.

> I'm wondering if there's a reason why one cannot inherit from
> immediate objects? (See description at:
> http://caml.inria.fr/pub/docs/manual-ocaml/manual005.html#ss:immediate-objects)
> Is it just a syntax problem because the 'inherit' keyword currently
> needs to take a class type, or is there a deeper reason?

I do not think it is a syntax problem.

Here is my understanding:
The type of a class and the type of an immediate object are essentially 
different. In other words, the self type of a class is open, thus extensible;
the self type of an immediate object is closed, thus not extensible. 

As written at:

http://caml.inria.fr/pub/docs/manual-ocaml/manual005.html#ss:immediate-objects)

the difference gives you different advantages; I suspect this is one reason. 

Best regards,
Keiko


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

* Re: [Caml-list] Why can't immediate objects be extended?
  2008-07-12 14:12 Why can't immediate objects be extended? Richard Jones
                   ` (2 preceding siblings ...)
  2008-07-14 14:38 ` Keiko Nakata
@ 2008-07-16  1:43 ` Jacques Garrigue
  3 siblings, 0 replies; 5+ messages in thread
From: Jacques Garrigue @ 2008-07-16  1:43 UTC (permalink / raw)
  To: rich; +Cc: caml-list

From: Richard Jones <rich@annexia.org>

> I'm wondering if there's a reason why one cannot inherit from
> immediate objects? (See description at:
> http://caml.inria.fr/pub/docs/manual-ocaml/manual005.html#ss:immediate-objects)
> Is it just a syntax problem because the 'inherit' keyword currently
> needs to take a class type, or is there a deeper reason?
> 
> This is the code I'd like to write (non-working, obviously):
[..]
>   let rec annotate = function
>     | (Leaf _ as t) -> t
>     | (Node (left, parent_obj, right) as t) ->
>         let obj = object
>   	  inherit (typeof parent_obj)
>   	  method str = string_of_tree t
>         end in
>         Node (annotate left, obj, annotate right)
[..]
> The problematic function is 'annotate'.  I believe I want annotate to
> have a type along these lines (again, this is not precisely OCaml code
> because I've used alpha to stand for '..'):
> 
>   val annotate : < 'a > tree -> < str : string; 'a > tree

There are several problems here.
What what you here is extensible records, with differential
rows (i.e. you need some way to ensure that str is not in 'a);
otherwise you would end up with a record with two str fiels, with
possibly different type. Extensible records are not available in
ocaml, and while objects allow structural typing of records, they do
not allow extension.

So the next question is why objects do not allow that. And here the
answer is very clear: this form of inheritance is incompatible with
subtyping.
Namely, by subtyping you can hide a field. So you could start
with a  <data: int; str: float> tree, coerce it to
<data: int> tree by subtyping, and then annotate it and obtain
a <data: int; str: string> tree.
If we were talking about records, there would be no problem,
but those are objects, so the definition of data may actually be
  method data = truncate self#str
If str now returns a string, this is broken.
This question is studied in details in Abadi and Cardelli's "A theory
of objects".

So there is no way you can inherit from an immediate object.
(The syntax "inherit object ... end" is not about immediate objects
but immediate classes (inside another class), and is not really
useful)

Going back to your original problem, another approach would be to
allow extension of objects _without overriding of methods_.
The trouble here is that it would require major changes in the type
system, to accomodate the differential rows mentioned above, for
something not directly connected with objects.

Now about workarounds. Since you problem is really a problem of
records, the simplest approach might be to use... records!

  type ('str,'cmt) parent_data = {str: 'str; cmt: 'cmt}

  let none = {str = (); cmt = ()}

  let annotate_data d (str:string) = {d with str = str}
  (* ('a, 'b) parent_data -> string -> (string, 'b) parent_data *)

Note here how the type is updated when you use the with construct.
This should provide you with the behaviour you want.
This may not be as polymorphic as you hoped (you need to know all the
fields w\you will use in advance), but providing a fully
polymorphic solution to the update problem requires a very complicated
type system (look at Didier Remy's papers)

Also, if you want lots of fields, this may be a good idea to use
a constraint to name parameters.

  type +'a parent_data =
    {str: 'str; cmt: 'cmt} constraint 'a = <str:'str; cmt:'cmt>

The explicit variance annotation is required here because it is not
automatically inferred for constrained parameters.
With this definition, the type of none becomes:

  < cmt : unit; str : unit > parent_data

Hope this helps,

     Jacques Garrigue


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

end of thread, other threads:[~2008-07-16  1:43 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-07-12 14:12 Why can't immediate objects be extended? Richard Jones
2008-07-12 14:26 ` [Caml-list] " Richard Jones
2008-07-14  1:47 ` Peng Zang
2008-07-14 14:38 ` Keiko Nakata
2008-07-16  1:43 ` Jacques Garrigue

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