* [Caml-list] typing mutually recursive classes @ 2012-10-24 18:03 Christopher Zimmermann 2012-10-24 18:40 ` Gabriel Scherer 0 siblings, 1 reply; 6+ messages in thread From: Christopher Zimmermann @ 2012-10-24 18:03 UTC (permalink / raw) To: caml-list 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 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] typing mutually recursive classes 2012-10-24 18:03 [Caml-list] typing mutually recursive classes Christopher Zimmermann @ 2012-10-24 18:40 ` Gabriel Scherer 2012-10-24 19:32 ` [Caml-list] " Christopher Zimmermann 0 siblings, 1 reply; 6+ messages in thread From: Gabriel Scherer @ 2012-10-24 18:40 UTC (permalink / raw) To: Christopher Zimmermann; +Cc: caml-list I don't really understand what you are trying to achieve with this #foo types. 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). 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. On Wed, Oct 24, 2012 at 8:03 PM, Christopher Zimmermann <madroach@gmerlin.de> 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 > > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa.inria.fr/sympa/arc/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs ^ permalink raw reply [flat|nested] 6+ messages in thread
* [Caml-list] Re: typing mutually recursive classes 2012-10-24 18:40 ` Gabriel Scherer @ 2012-10-24 19:32 ` Christopher Zimmermann 2012-10-24 20:35 ` Didier Cassirame [not found] ` <CAPFanBHdh8xKsZC6fs2oXEOitjKLhZzVUdVmYT+6d0jL46YM0w@mail.gmail.com> 0 siblings, 2 replies; 6+ messages in thread From: Christopher Zimmermann @ 2012-10-24 19:32 UTC (permalink / raw) To: caml-list On Wed, 24 Oct 2012 20:40:27 +0200 Gabriel Scherer <gabriel.scherer@gmail.com> 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 > <madroach@gmerlin.de> 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 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Re: typing mutually recursive classes 2012-10-24 19:32 ` [Caml-list] " Christopher Zimmermann @ 2012-10-24 20:35 ` Didier Cassirame 2012-10-24 21:30 ` Didier Cassirame [not found] ` <CAPFanBHdh8xKsZC6fs2oXEOitjKLhZzVUdVmYT+6d0jL46YM0w@mail.gmail.com> 1 sibling, 1 reply; 6+ messages in thread From: Didier Cassirame @ 2012-10-24 20:35 UTC (permalink / raw) To: Christopher Zimmermann; +Cc: caml-list [-- Attachment #1: Type: text/plain, Size: 3972 bytes --] Hi, Your first two examples compile without problem on my system, using either v. 3.11.2 or 4.00. If you use a parameterized registry class on the element type, you will not be able to store polymorphic values, which is, I reckon, what you probably want to achieve. I don't think there's a way to avoid casting the parameters of set to the #element superclass outside the set method. If you only have one final element class, just use the parameterized version of the registry, or replace the register method by a private register_elem method, and add a public register method in the subclass, doing the cast. Something like that : module P = struct class element id (registry :registry) = object method registry = registry end and registry = object val mutable set : element list = [] method register_elem : element -> unit = fun s -> set <- s :: set end end module I = struct class element id registry = let r = (registry :> P.registry) in object(self) inherit P.element id r as super end class registry = object(self) inherit P.registry as super method register : element -> unit = fun x -> super#register_elem (x :> P.element) end end Cheers, Didier 2012/10/24 Christopher Zimmermann <madroach@gmerlin.de> > On Wed, 24 Oct 2012 20:40:27 +0200 > Gabriel Scherer <gabriel.scherer@gmail.com> 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 > > <madroach@gmerlin.de> 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 > > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa.inria.fr/sympa/arc/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > [-- Attachment #2: Type: text/html, Size: 6208 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Re: typing mutually recursive classes 2012-10-24 20:35 ` Didier Cassirame @ 2012-10-24 21:30 ` Didier Cassirame 0 siblings, 0 replies; 6+ messages in thread From: Didier Cassirame @ 2012-10-24 21:30 UTC (permalink / raw) To: Christopher Zimmermann; +Cc: caml-list [-- Attachment #1: Type: text/plain, Size: 339 bytes --] 2012/10/24 Didier Cassirame <didier.cassirame@gmail.com> wrote > I don't think there's a way to avoid casting the parameters of set to the > #element superclass outside the set method. (...) > Here, please read "I don't think there's a way to avoid casting the parameters to the #element superclass outside the register method". didier [-- Attachment #2: Type: text/html, Size: 670 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
[parent not found: <CAPFanBHdh8xKsZC6fs2oXEOitjKLhZzVUdVmYT+6d0jL46YM0w@mail.gmail.com>]
* [Caml-list] typing mutually recursive classes [not found] ` <CAPFanBHdh8xKsZC6fs2oXEOitjKLhZzVUdVmYT+6d0jL46YM0w@mail.gmail.com> @ 2012-10-24 21:04 ` Gabriel Scherer 0 siblings, 0 replies; 6+ messages in thread From: Gabriel Scherer @ 2012-10-24 21:04 UTC (permalink / raw) To: caml users (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 <madroach@gmerlin.de> wrote: > On Wed, 24 Oct 2012 20:40:27 +0200 > Gabriel Scherer <gabriel.scherer@gmail.com> 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 >> <madroach@gmerlin.de> 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 ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2012-10-24 21:31 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-10-24 18:03 [Caml-list] typing mutually recursive classes Christopher Zimmermann 2012-10-24 18:40 ` Gabriel Scherer 2012-10-24 19:32 ` [Caml-list] " Christopher Zimmermann 2012-10-24 20:35 ` Didier Cassirame 2012-10-24 21:30 ` Didier Cassirame [not found] ` <CAPFanBHdh8xKsZC6fs2oXEOitjKLhZzVUdVmYT+6d0jL46YM0w@mail.gmail.com> 2012-10-24 21:04 ` [Caml-list] " Gabriel Scherer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox