caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Jacques Garrigue <garrigue@math.nagoya-u.ac.jp>
To: rich@annexia.org
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] Why can't immediate objects be extended?
Date: Wed, 16 Jul 2008 10:43:08 +0900 (JST)	[thread overview]
Message-ID: <20080716.104308.240648623.garrigue@math.nagoya-u.ac.jp> (raw)
In-Reply-To: <20080712141200.GA8634@annexia.org>

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


      parent reply	other threads:[~2008-07-16  1:43 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-07-12 14:12 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 message]

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=20080716.104308.240648623.garrigue@math.nagoya-u.ac.jp \
    --to=garrigue@math.nagoya-u.ac.jp \
    --cc=caml-list@inria.fr \
    --cc=rich@annexia.org \
    /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).