From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by sympa.inria.fr (Postfix) with ESMTPS id 058357EC41 for ; Wed, 24 Oct 2012 23:05:17 +0200 (CEST) Received-SPF: None (mail1-smtp-roc.national.inria.fr: no sender authenticity information available from domain of gabriel.scherer@gmail.com) identity=pra; client-ip=209.85.223.182; receiver=mail1-smtp-roc.national.inria.fr; envelope-from="gabriel.scherer@gmail.com"; x-sender="gabriel.scherer@gmail.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail1-smtp-roc.national.inria.fr: domain of gabriel.scherer@gmail.com designates 209.85.223.182 as permitted sender) identity=mailfrom; client-ip=209.85.223.182; receiver=mail1-smtp-roc.national.inria.fr; envelope-from="gabriel.scherer@gmail.com"; x-sender="gabriel.scherer@gmail.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail1-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@mail-ie0-f182.google.com) identity=helo; client-ip=209.85.223.182; receiver=mail1-smtp-roc.national.inria.fr; envelope-from="gabriel.scherer@gmail.com"; x-sender="postmaster@mail-ie0-f182.google.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AicEAMdWiFDRVd+2m2dsb2JhbABEwHEDgQEIIwEBAQEBCAkLCRQngh4BAQEEEgITGQEbDw8DDAYQDS4hAQERAQUBFgYGEwgTB4dPAQMPnUdgCQOMKIJ2hH4KGScNWYh1AQUMim5nYoYLA5QegVWLKYMvFimEEw X-IronPort-AV: E=Sophos;i="4.80,642,1344204000"; d="scan'208";a="178797281" Received: from mail-ie0-f182.google.com ([209.85.223.182]) by mail1-smtp-roc.national.inria.fr with ESMTP/TLS/RC4-SHA; 24 Oct 2012 23:05:16 +0200 Received: by mail-ie0-f182.google.com with SMTP id k10so2428719iea.27 for ; Wed, 24 Oct 2012 14:05:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type; bh=qGHj53UYs7Nwg19fw5X6tW+BzysYxgldw31kwRcy0Pc=; b=J+fP/jcyfzghDDshYQdB0UDpOH0ejq/bPjdHb5VSgrVEfAVdnKu4nJSj2lAWkEEcMu VdrZU0hqI1Ea3xOqRLbWZtE8Di7auoIRwxXr6/upPS7hYKqUJz1RuYDvDqeYNhPyyba6 sT0ip8S5gzkNfIGF3Fzq8TxakXvPyvLIXfjX7tvAtsjAWEGdr+xW6Jw8Us5GhWOl8eAs PqsE8YW4H+1ZDUA+jt5tb4uEJKwuuHu9RvFzwQ8dgIwYIrgSm3ldK/jNOOW/Zo6tSShq FpU5+CxBwq6uWRVo2cqK0RWfG48n23723GmUNi/brZw5h4fPXkr3tphcrpF4c8w1QtYK cggg== Received: by 10.50.140.97 with SMTP id rf1mr2370528igb.70.1351112715238; Wed, 24 Oct 2012 14:05:15 -0700 (PDT) MIME-Version: 1.0 Received: by 10.50.65.9 with HTTP; Wed, 24 Oct 2012 14:04:35 -0700 (PDT) In-Reply-To: References: <20121024200310.9c639f43a97263423e113500@gmerlin.de> <20121024213213.2e447165b7c4ea9ad9d8e154@gmerlin.de> From: Gabriel Scherer Date: Wed, 24 Oct 2012 23:04:35 +0200 Message-ID: To: caml users Content-Type: text/plain; charset=ISO-8859-1 Subject: [Caml-list] typing mutually recursive classes (I previously sent this reply to Christopher privately, by mistake. Apologies for double-sending.) I'm no expert of the typing of the object-oriented features of OCaml, but my understanding is that #foo is a syntactic sugar for the expansion of foo's type with an added row variable. For example, if "foo" has the object type < a : int; b : bool >, #foo would be a synonym for < a : int; b : bool; .. >. For #foo to mean anything, "foo" must be already defined, so I'm not surprised that it fails when defining a recursive class. The following already fails: class test = object method id : 'a. (#test as 'a) -> 'a = fun x -> x end What would you expand #test to in this definition? On the other hand, just using "test" makes sense in a recursive type. Note that you might be able to work around this limitation by using recursive modules as a way to "pre-declare" the interface of your classes. The following type-checks: module rec M : sig class element : 'a -> #M.registry -> object method registry : M.registry end class registry : object method register : 'a . (#element as 'a) -> unit end end = struct class element id (registry : #M.registry) = object method registry = (registry :> M.registry) end class registry = object val mutable set = [] method register :'a. (#element as 'a) -> unit = fun s -> set <- (s :> element) :: set end end Now, is adding recursive modules to an already too complicated typing problem a good idea? Frankly, I don't think so. I would personally go for the version without #foo types and with explicit casting. On Wed, Oct 24, 2012 at 9:32 PM, Christopher Zimmermann wrote: > On Wed, 24 Oct 2012 20:40:27 +0200 > Gabriel Scherer wrote: > >> I don't really understand what you are trying to achieve with this >> #foo types. > > It's the simplest statement possible to demonstrate the typing error I > ran into. Even simpler: > > class type a = object end > and b = > object > method foo: 'a. (#a as 'a) -> unit > end > > fails, but > > class type a = object end > class type b = > object > method foo: 'a. (#a as 'a) -> unit > end > > > works fine. Why? > >> What would even be the type of "set" in your example? You >> cannot hold a mutable reference to a polymorphic type (#element list), >> so I'm not sure what you would have but (element list). > That's correct. It should read > val mutable set = [] > method register :'a. (#element as 'a) -> unit = > fun s -> > set <- (s : #element :> element) :: set > >> If you're >> going to coerce your elements into the common (element) supertype >> anyway, why insist on having flexible bounds? You could just use >> (registry) and (element), coerce when needed (foo :> element), and get >> rid of those pesky typing issues. > > That's my current workaround for this issue. But I would prefer a > solution where the coercion happens in the registry. > >> >> On Wed, Oct 24, 2012 at 8:03 PM, Christopher Zimmermann >> wrote: >> > Hi, >> > >> > I have a problem with typing a system of mutually recursive classes. >> > >> > This piece of code fails to compile: >> > >> > class a = >> > object end >> > and b = >> > object >> > method foo: a -> int = >> > fun s -> 3 >> > end;; >> > >> > Error: The universal type variable 'a cannot be generalized: >> > it escapes its scope. >> > >> > >> > But this compiles fine: >> > >> > class a = >> > object end >> > class b = >> > object >> > method foo: 'a. (#a as 'a) -> int = >> > fun s -> 3 >> > end;; >> > >> > >> > What I actually want to do is this: >> > >> > class element id (registry :#registry) = >> > object >> > method registry = registry >> > end >> > >> > and registry = >> > object >> > val set = [] >> > method register :'a. (#element as 'a) -> unit = >> > fun s -> >> > set <- s :: set >> > end >> > >> > >> > Any ideas how to do this without parametrizing the classes? >> > >> > Christopher