caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] copy of parametrized object
@ 2003-06-24 11:15 Bow-Yaw Wang
  2003-06-24 12:36 ` Jacques Garrigue
  0 siblings, 1 reply; 7+ messages in thread
From: Bow-Yaw Wang @ 2003-06-24 11:15 UTC (permalink / raw)
  To: caml-list


Hi,

I'd like to know how to make independent copies of parameterized 
objects. Consider the following example:

# class ['a] t = object method id (x:'a) = x end;;
class ['a] t : object method id : 'a -> 'a end
# let o = new t;;
val o : '_a t = <obj>
# let p = Oo.copy o;;
val p : < id : '_a -> '_a > = <obj>
# o#id 1;;
- : int = 1

After defining a simple parameterized class t, I create an
object o of type '_a t and make p as a copy. After the type 
'_a is instantiated to int, I'd expect p to retain its type
< id : '_a -> '_a >. However, 

# p;;
- : < id : int -> int > = <obj>

So my questions are:

1. Is there a way to make a copy of o so that it can be 
instantiated differently?
2. If not, is there any type-theoretic explanation? I'm
just curious if it may make type system unsound.

I'm aware of polymorphic methods. Unfortunately, the
project I'm working on uses parameterized classes. Using
polymorphic methods doesn't seem to be feasible at the
moment. :(

Thanks in advance,

Bow-Yaw

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] copy of parametrized object
  2003-06-24 11:15 [Caml-list] copy of parametrized object Bow-Yaw Wang
@ 2003-06-24 12:36 ` Jacques Garrigue
  2003-06-24 12:57   ` Stefano Zacchiroli
  2003-06-24 20:33   ` Bow-Yaw Wang
  0 siblings, 2 replies; 7+ messages in thread
From: Jacques Garrigue @ 2003-06-24 12:36 UTC (permalink / raw)
  To: bywang; +Cc: caml-list

From: Bow-Yaw Wang <bywang@saul.cis.upenn.edu>

> I'd like to know how to make independent copies of parameterized 
> objects. Consider the following example:
> 
> # class ['a] t = object method id (x:'a) = x end;;
> class ['a] t : object method id : 'a -> 'a end
> # let o = new t;;
> val o : '_a t = <obj>
> # let p = Oo.copy o;;
> val p : < id : '_a -> '_a > = <obj>
> # o#id 1;;
> - : int = 1
> 
> After defining a simple parameterized class t, I create an
> object o of type '_a t and make p as a copy. After the type 
> '_a is instantiated to int, I'd expect p to retain its type
> < id : '_a -> '_a >. However, 
> 
> # p;;
> - : < id : int -> int > = <obj>

That's just the point of non-generalized variables: if you instantiate
them somewhere, the type is propagated everywhere. So as long as the
type of o is '_a t, there is no hope.

> So my questions are:
> 
> 1. Is there a way to make a copy of o so that it can be 
> instantiated differently?

No.

> 2. If not, is there any type-theoretic explanation? I'm
> just curious if it may make type system unsound.

In this case, this is pretty simple: '_a is not a polymorphic
variable, this is just a monomorphic type which is not yet known.
If you copy it, you just get a pointer to the same type.

As to why o has such a non-polymorphic type, this is due to the evily
famous value restriction: any function application result is
non-polymorphic, and an object construtctor is seen as a function
application.

A dangerous definition would be:

class ['a] t =
  object
    val mutable r = None
    method id (x:'a) =
      match r with Some y -> y | None -> r <- Some x; x
  end;;

> I'm aware of polymorphic methods. Unfortunately, the
> project I'm working on uses parameterized classes. Using
> polymorphic methods doesn't seem to be feasible at the
> moment. :(

I wonder what you need exactly.

Jacques

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] copy of parametrized object
  2003-06-24 12:36 ` Jacques Garrigue
@ 2003-06-24 12:57   ` Stefano Zacchiroli
  2003-06-24 20:33   ` Bow-Yaw Wang
  1 sibling, 0 replies; 7+ messages in thread
From: Stefano Zacchiroli @ 2003-06-24 12:57 UTC (permalink / raw)
  To: caml-list

On Tue, Jun 24, 2003 at 09:36:08PM +0900, Jacques Garrigue wrote:
> famous value restriction: any function application result is
> non-polymorphic, and an object construtctor is seen as a function
> application.

BTW (but surely a bit off-thread), could you remember me for which
reason object constructors are not considered functions consistently in
the ocaml language? Why is currently not possible to do:

  type foo = Foo of int | Bar of int
  List.map Foo [1; 2; 3; 4]

?

TIA,
Cheers

-- 
Stefano Zacchiroli  --  Master in Computer Science @ Uni. Bologna, Italy
zack@{cs.unibo.it,debian.org,bononia.it}  -  http://www.bononia.it/zack/
"  I know you believe you understood what you think I said, but I am not
sure you realize that what you heard is not what I meant!  " -- G.Romney

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] copy of parametrized object
  2003-06-24 12:36 ` Jacques Garrigue
  2003-06-24 12:57   ` Stefano Zacchiroli
@ 2003-06-24 20:33   ` Bow-Yaw Wang
  2003-06-25  0:25     ` [Caml-list] Visitor pattern (was copy of parametrized object) Jacques Garrigue
  1 sibling, 1 reply; 7+ messages in thread
From: Bow-Yaw Wang @ 2003-06-24 20:33 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: caml-list


Reply in text.

> From: Bow-Yaw Wang <bywang@saul.cis.upenn.edu>
> 
> > I'd like to know how to make independent copies of parameterized 
> > objects. Consider the following example:
> > 
> > # class ['a] t = object method id (x:'a) = x end;;
> > class ['a] t : object method id : 'a -> 'a end
> > # let o = new t;;
> > val o : '_a t = <obj>
> > # let p = Oo.copy o;;
> > val p : < id : '_a -> '_a > = <obj>
> > # o#id 1;;
> > - : int = 1
> > 
> > After defining a simple parameterized class t, I create an
> > object o of type '_a t and make p as a copy. After the type 
> > '_a is instantiated to int, I'd expect p to retain its type
> > < id : '_a -> '_a >. However, 
> > 
> > # p;;
> > - : < id : int -> int > = <obj>
> 
> That's just the point of non-generalized variables: if you instantiate
> them somewhere, the type is propagated everywhere. So as long as the
> type of o is '_a t, there is no hope.

But is it necessary to propagate everywhere? If I create 
another t object, it is of type '_a t too. But the new
object remains intact while the copied object changes its 
type when I instantiate the original.

> > So my questions are:
> > 
> > 1. Is there a way to make a copy of o so that it can be 
> > instantiated differently?
> 
> No.

Thanks for the info. It is a little disappointing, though.

> 
> > 2. If not, is there any type-theoretic explanation? I'm
> > just curious if it may make type system unsound.
> 
> In this case, this is pretty simple: '_a is not a polymorphic
> variable, this is just a monomorphic type which is not yet known.
> If you copy it, you just get a pointer to the same type.

'_a is not a polymorphic variable, and I didn't want it to be.
I think what I want is to have a pointer to a new monomorphic
type variable in copies. 

[snip]

> I wonder what you need exactly.

It is about a simplified visitor design pattern. Let's say
we have:

class ['value, 'visitor] a = 
  object 
    constraint 'visitor = < in_a : unit -> 'value; .. > 
    method invite (v : 'visitor) = v#in_a () 
  end;;

class virtual ['value] visitor_t = 
  object 
    method virtual in_a : unit -> 'value
  end;;

I can create two different visitors:

class int_visitor_t = 
  object 
    inherit [int] visitor_t 
    method in_a () = 0 
  end;;

let int_v = new int_visitor_t;;

class string_visitor_t = 
  object 
    inherit [string] visitor_t 
    method in_a () = "a" 
  end;;

let str_v = new string_visitor_t;;

Suppose I have two objects:

let x = new a;;
let y = Oo.copy x;;

I want both int_v and str_v to be invited. I can do

x#invite int_v;;

But then x will be instantiated and cannot apply str_v
again. So I thought a copy of x might be used in
applying str_v. But it turns out the copy y will be 
instantiated as well. 

Now since the visitor type is constrained, it cannot
be polymorphic in class a. A simple solution (IMHO)
is to have an independent copy of x. It doesn't seem
to be necessary to tie the monomorphic type variables
of the copy to the original. And it would make the
previous visitor pattern implementation cleaner. 
Otherwise, I'll have to build another x from scratch.

Bow-Yaw

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [Caml-list] Visitor pattern (was copy of parametrized object)
  2003-06-24 20:33   ` Bow-Yaw Wang
@ 2003-06-25  0:25     ` Jacques Garrigue
  2003-06-25  1:06       ` Bow-Yaw Wang
  0 siblings, 1 reply; 7+ messages in thread
From: Jacques Garrigue @ 2003-06-25  0:25 UTC (permalink / raw)
  To: bywang; +Cc: caml-list

From: Bow-Yaw Wang <bywang@saul.cis.upenn.edu>

> > That's just the point of non-generalized variables: if you instantiate
> > them somewhere, the type is propagated everywhere. So as long as the
> > type of o is '_a t, there is no hope.
> 
> But is it necessary to propagate everywhere? If I create 
> another t object, it is of type '_a t too. But the new
> object remains intact while the copied object changes its 
> type when I instantiate the original.

Sure, if you create a new object you know for sure it doesn't share
data with the first one, so you're safe.

You can also write

# let new_t () = new t;;
val new_t : unit -> 'a t = <fun>
# let o = new_t ();;
val o : '_a t = <obj>

See how new_t has a polymorphic type?
Calling [new t] is just equivalent to [new_t ()]. (Actually this
generates almost the same code). So no surprise they should be typed
identically.

> > I wonder what you need exactly.
> 
> It is about a simplified visitor design pattern. Let's say
> we have:
> 
> class ['value, 'visitor] a = 
>   object 
>     constraint 'visitor = < in_a : unit -> 'value; .. > 
>     method invite (v : 'visitor) = v#in_a () 
>   end;;

If this is really what you want, then you must use a polymorphic method.
I switch the definition order for simplicity.

class virtual ['value] visitor_t = 
  object 
    method virtual in_a : unit -> 'value
  end;;

class a = 
  object 
    method invite : 'visitor 'value. ('value #visitor_t as 'visitor) -> 'value
        = fun v -> v#in_a () 
  end;;

Then all the following will work:
 
> I can create two different visitors:
> 
> class int_visitor_t = 
>   object 
>     inherit [int] visitor_t 
>     method in_a () = 0 
>   end;;
> 
> let int_v = new int_visitor_t;;
> 
> class string_visitor_t = 
>   object 
>     inherit [string] visitor_t 
>     method in_a () = "a" 
>   end;;
> 
> let str_v = new string_visitor_t;;
> 
> Suppose I have two objects:
> 
> let x = new a;;
> let y = Oo.copy x;;
No need to copy (this is wrong anyway, copying is just unrelated to typing).

> I want both int_v and str_v to be invited. I can do
> 
> x#invite int_v;;
and
  x#invite str_v;;
will work too.

> Now since the visitor type is constrained, it cannot
> be polymorphic in class a. A simple solution (IMHO)
> is to have an independent copy of x. It doesn't seem
> to be necessary to tie the monomorphic type variables
> of the copy to the original. And it would make the
> previous visitor pattern implementation cleaner. 
> Otherwise, I'll have to build another x from scratch.

There is no notion of independent copy that I know.
It is plain necessary to tie the monomorphic type variables of the
copy to the original, as the example in my previous mail showed.
So if you want to stick to you weaker approach, you'll have to build
another x from scratch.

By the way, I'm not sure this coding of the visitor pattern is a good
programming approach in ocaml: most things can be done in a simpler
way using a function rather than a visitor, since anyway generally all
cases of a visitor have the same return type.

# class a = 
  object 
    method invite : 'cases 'value. (([> `A] as 'cases) -> 'value) -> 'value =
      fun f ->  f `A
  end;;
class a : object method invite : ([> `A ] -> 'a) -> 'a end

The advantage is two-fold: you don't need to define a class for each
visitor (this is a pain), and now the variables 'cases and 'value are
really independent, so if you want to define the class a in a more
extensible way, you can write:

# class ['cases] a = 
  object 
    method invite : 'value. (([> `A] as 'cases) -> 'value) -> 'value =
      fun f ->  f `A
  end;;
class ['a] a :
  object constraint 'a = [> `A ] method invite : ('a -> 'b) -> 'b end
# let x = new a;;
val x : _[> `A ] a = <obj>
# x#invite (fun `A -> 0);;
- : int = 0
# x#invite (fun `A -> "a");;
- : string = "a"

Another remark is that in most cases there is no need to wrap your
variant type in an object anyway, and then you don't need classes at
all :-)

Jacques Garrigue

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] Visitor pattern (was copy of parametrized object)
  2003-06-25  0:25     ` [Caml-list] Visitor pattern (was copy of parametrized object) Jacques Garrigue
@ 2003-06-25  1:06       ` Bow-Yaw Wang
  2003-06-25  2:37         ` John Max Skaller
  0 siblings, 1 reply; 7+ messages in thread
From: Bow-Yaw Wang @ 2003-06-25  1:06 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: caml-list


Thanks a lot. Using polymorphic variants solves the problem
beautifully. I'll reorganize my code. Thanks!

Bow-Yaw

> By the way, I'm not sure this coding of the visitor pattern is a good
> programming approach in ocaml: most things can be done in a simpler
> way using a function rather than a visitor, since anyway generally all
> cases of a visitor have the same return type.
> 
> # class a = 
>   object 
>     method invite : 'cases 'value. (([> `A] as 'cases) -> 'value) -> 'value =
>       fun f ->  f `A
>   end;;
> class a : object method invite : ([> `A ] -> 'a) -> 'a end
> 
> The advantage is two-fold: you don't need to define a class for each
> visitor (this is a pain), and now the variables 'cases and 'value are
> really independent, so if you want to define the class a in a more
> extensible way, you can write:
> 
> # class ['cases] a = 
>   object 
>     method invite : 'value. (([> `A] as 'cases) -> 'value) -> 'value =
>       fun f ->  f `A
>   end;;
> class ['a] a :
>   object constraint 'a = [> `A ] method invite : ('a -> 'b) -> 'b end
> # let x = new a;;
> val x : _[> `A ] a = <obj>
> # x#invite (fun `A -> 0);;
> - : int = 0
> # x#invite (fun `A -> "a");;
> - : string = "a"
> 
> Another remark is that in most cases there is no need to wrap your
> variant type in an object anyway, and then you don't need classes at
> all :-)
> 
> Jacques Garrigue

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] Visitor pattern (was copy of parametrized object)
  2003-06-25  1:06       ` Bow-Yaw Wang
@ 2003-06-25  2:37         ` John Max Skaller
  0 siblings, 0 replies; 7+ messages in thread
From: John Max Skaller @ 2003-06-25  2:37 UTC (permalink / raw)
  To: Bow-Yaw Wang; +Cc: Jacques Garrigue, caml-list

Bow-Yaw Wang wrote:

> Thanks a lot. Using polymorphic variants solves the problem
> beautifully. I'll reorganize my code. Thanks!
 
I use polymorphic variants almost exclusively.

They're much more expressive than the ordinary kind.

They're generally easier to program with too,
but there is one downside, and it is a BIG downside.

When you make a mistake, and your variants are
large, you can get 200++ line error messages.
The situation has been improved so that now
the compiler sometimes recognizes when you left
out a case (xxx has tag AAA but yyy doesn't).

I suggest that polymorphic variants require

a lazier, rapid prototyping style of programming:
build and test OFTEN so you know that when
there is an error, it had to be in the last
change you made. That way, you can often
ignore the content of the error message,
and just look direcly at the code for
an error.

Also: you will need to use type annotations
a bit more heavily to help localise errors.

-- 
John Max Skaller, mailto:skaller@ozemail.com.au
snail:10/1 Toxteth Rd, Glebe, NSW 2037, Australia.
voice:61-2-9660-0850


-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2003-06-25  2:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-06-24 11:15 [Caml-list] copy of parametrized object Bow-Yaw Wang
2003-06-24 12:36 ` Jacques Garrigue
2003-06-24 12:57   ` Stefano Zacchiroli
2003-06-24 20:33   ` Bow-Yaw Wang
2003-06-25  0:25     ` [Caml-list] Visitor pattern (was copy of parametrized object) Jacques Garrigue
2003-06-25  1:06       ` Bow-Yaw Wang
2003-06-25  2:37         ` John Max Skaller

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).