caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Jacques Garrigue <garrigue@kurims.kyoto-u.ac.jp>
To: bywang@saul.cis.upenn.edu
Cc: caml-list@inria.fr
Subject: [Caml-list] Visitor pattern (was copy of parametrized object)
Date: Wed, 25 Jun 2003 09:25:36 +0900	[thread overview]
Message-ID: <20030625092536F.garrigue@kurims.kyoto-u.ac.jp> (raw)
In-Reply-To: <200306242033.h5OKX2Xj000711@saul.cis.upenn.edu>

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


  reply	other threads:[~2003-06-25  0:25 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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     ` Jacques Garrigue [this message]
2003-06-25  1:06       ` [Caml-list] Visitor pattern (was copy of parametrized object) Bow-Yaw Wang
2003-06-25  2:37         ` John Max Skaller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20030625092536F.garrigue@kurims.kyoto-u.ac.jp \
    --to=garrigue@kurims.kyoto-u.ac.jp \
    --cc=bywang@saul.cis.upenn.edu \
    --cc=caml-list@inria.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).