Version française
Home     About     Download     Resources     Contact us    
Browse thread
Re: [Caml-list] copy of parametrized object
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Jacques Garrigue <garrigue@k...>
Subject: [Caml-list] Visitor pattern (was copy of parametrized object)
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