From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: X-Spam-Status: No, score=0.4 required=5.0 tests=AWL,DNS_FROM_RFC_ABUSE autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by yquem.inria.fr (Postfix) with ESMTP id DB91BBB84 for ; Wed, 16 Jul 2008 03:43:36 +0200 (CEST) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ApoEALjvfEjAXQIm/2dsb2JhbACwNw X-IronPort-AV: E=Sophos;i="4.30,369,1212357600"; d="scan'208";a="13147832" Received: from discorde.inria.fr ([192.93.2.38]) by mail2-smtp-roc.national.inria.fr with ESMTP; 16 Jul 2008 03:43:18 +0200 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by discorde.inria.fr (8.13.6/8.13.6) with ESMTP id m6G1hGdc012886 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Wed, 16 Jul 2008 03:43:18 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ApoEAATvfEiCNhAB/2dsb2JhbACwNQ X-IronPort-AV: E=Sophos;i="4.30,369,1212357600"; d="scan'208";a="27358123" Received: from kurims.kurims.kyoto-u.ac.jp ([130.54.16.1]) by mail4-smtp-sop.national.inria.fr with ESMTP; 16 Jul 2008 03:43:17 +0200 Received: from localhost (orion [130.54.16.5]) by kurims.kurims.kyoto-u.ac.jp (8.13.8/8.13.8) with ESMTP id m6G1h67Q019877; Wed, 16 Jul 2008 10:43:06 +0900 (JST) Date: Wed, 16 Jul 2008 10:43:08 +0900 (JST) Message-Id: <20080716.104308.240648623.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? From: Jacques Garrigue In-Reply-To: <20080712141200.GA8634@annexia.org> References: <20080712141200.GA8634@annexia.org> X-Mailer: Mew version 5.2 on Emacs 22.1 / Mule 5.0 (SAKAKI) Mime-Version: 1.0 Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Miltered: at discorde with ID 487D5234.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; syntax:01 node:01 node:01 ocaml:01 val:01 ocaml:01 subtyping:01 subtyping:01 abadi:01 syntax:01 overriding:01 workarounds:01 didier:01 remy's:01 polymorphic:01 From: Richard Jones > 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 tree, coerce it to tree by subtyping, and then annotate it and obtain a 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 = 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