caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [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

* [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

* 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

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;
as well as URLs for NNTP newsgroup(s).