caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* state pattern...
@ 2005-06-26 19:57 Michael Wohlwend
  2005-06-26 22:13 ` [Caml-list] " james woodyatt
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Wohlwend @ 2005-06-26 19:57 UTC (permalink / raw)
  To: caml-list

Hi,

although it can be implemented with a 'match', just of interest, can somebody 
help me with my oo implementation of the state-pattern?

this does not work (any many other tries also didn't :-)

class ['a] context (start_state : 'a)= object(this)
 constraint 'a = #state
 val mutable state = start_state
 method set_state st = state <- st
 method show = state#show
 method run = state#handle this 
end

and virtual state = object
  method virtual show : unit
  method virtual handle : state #context -> #state -> unit
end;;

class state1 = object (this)
 inherit state
 method show = print_endline "state1"
 method handle context = context#set_state (new state2)
end
and state2 = object (this)
 inherit state
 method show = print_endline "state2"
 method handle context = context#set_state (new state1)
end;;

for this to work:
let c = new context (new state1) in
c#show; (* state1 *)
c#run; (* change state *)
c#show; (* state2 *)
c#run;


cheers,
 Michael


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

* Re: [Caml-list] state pattern...
  2005-06-26 19:57 state pattern Michael Wohlwend
@ 2005-06-26 22:13 ` james woodyatt
  2005-06-26 22:45   ` Michael Wohlwend
  2005-06-27 23:23   ` Michael Wohlwend
  0 siblings, 2 replies; 7+ messages in thread
From: james woodyatt @ 2005-06-26 22:13 UTC (permalink / raw)
  To: Michael Wohlwend; +Cc: caml-list

On 26 Jun 2005, at 12:57, Michael Wohlwend wrote:
>
> although it can be implemented with a 'match', just of interest, can 
> somebody
> help me with my oo implementation of the state-pattern?

I tend to work in the functional style first, then transfer what I've 
done into imperative style if there is a performance gain to be had by 
it.  Here's what I would do to make something like what you want:

class type state =
     object('self)
         method show: unit
         method next: 'self
     end

class ['state] context s =
     object(_:'self)
         val state_: #state = s
         method show = state_#show
         method run = {< state_ = state_#next >}
     end

class state1 =
     object
         method show = print_endline "state1"
         method next = new state2
     end
and state2 =
     object
         method show = print_endline "state2"
         method next = new state1
     end

let c = new context (new state1) in
c#show;
let c = c#run in
c#show;
let c = c#run in
c#show

You get into a problem pretty quickly if the state class needs to be 
aware of the full type of the context in order to compute the next 
state.  What that really means is that the context *is* the state, and 
you need to rethink how the pattern is supposed to be applied to your 
design.


-- 
j h woodyatt <jhw@wetware.com>
that's my village calling... no doubt, they want their idiot back.


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

* Re: [Caml-list] state pattern...
  2005-06-26 22:13 ` [Caml-list] " james woodyatt
@ 2005-06-26 22:45   ` Michael Wohlwend
  2005-06-27 23:23   ` Michael Wohlwend
  1 sibling, 0 replies; 7+ messages in thread
From: Michael Wohlwend @ 2005-06-26 22:45 UTC (permalink / raw)
  To: caml-list, james woodyatt

On Monday 27 June 2005 00:13, james woodyatt wrote:
> I tend to work in the functional style first, then transfer what I've
> done into imperative style if there is a performance gain to be had by
> it.  Here's what I would do to make something like what you want:

really very helpful, your code snippet.

>
> You get into a problem pretty quickly if the state class needs to be
> aware of the full type of the context in order to compute the next
> state.  What that really means is that the context *is* the state, and
> you need to rethink how the pattern is supposed to be applied to your
> design.

that's why in my code the function which does the work of the state and sets 
the new one gets the context as a parameter, but I didn't get this right.
I know that the pattern has it's limitations...

thanks
 Michael


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

* Re: [Caml-list] state pattern...
  2005-06-26 22:13 ` [Caml-list] " james woodyatt
  2005-06-26 22:45   ` Michael Wohlwend
@ 2005-06-27 23:23   ` Michael Wohlwend
  2005-06-28  0:54     ` Jacques Garrigue
  1 sibling, 1 reply; 7+ messages in thread
From: Michael Wohlwend @ 2005-06-27 23:23 UTC (permalink / raw)
  To: caml-list

On Monday 27 June 2005 00:13, james woodyatt wrote:
> I tend to work in the functional style first, then transfer what I've
> done into imperative style if there is a performance gain to be had by
> it.  Here's what I would do to make something like what you want:
> ...

I have modified the code, so that some method(s) of the state classes get the 
context class as parameter; I think it took me 3 hour to get the type 
definitions working :-)

Can this be done simpler? It works, although I don't completly understand all 
of it :-) 
-------------------------
class type param =
 object 
 method name : string
 end

class type state =
 object('self)
  method show: 'a. (#param as 'a) -> unit
  method next: 'self
 end

class ['state] context s =
 object (this:'self)
 val name = "context"
 val state_: #state = s 
 method name = name
 method show: unit = state_#show this
 method run = {< state_ = state_#next >}
 end

class state1 = object (this)
 method show: 'a. (#param as 'a) -> unit = fun c -> print_endline ("state1 of 
" ^ c#name)
 method next = new state2 
end
and state2 = object (this)
 method show: 'a. (#param  as 'a) -> unit = fun c -> print_endline ("state2 of 
" ^ c#name) 
 method next = new state1 
end;;

let c = new context (new state1) in
c#show;
let c = c#run in
c#show

----------------------------


thanks,
 Michael


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

* Re: [Caml-list] state pattern...
  2005-06-27 23:23   ` Michael Wohlwend
@ 2005-06-28  0:54     ` Jacques Garrigue
  2005-06-28 12:24       ` Michael Wohlwend
  0 siblings, 1 reply; 7+ messages in thread
From: Jacques Garrigue @ 2005-06-28  0:54 UTC (permalink / raw)
  To: micha-1; +Cc: caml-list

From: Michael Wohlwend <micha-1@fantasymail.de>

> I have modified the code, so that some method(s) of the state
> classes get the context class as parameter; I think it took me 3
> hour to get the type definitions working :-)
> 
> Can this be done simpler? It works, although I don't completly
> understand all of it :-) 

There is a variety of things you could do to simplify your code.
If you want to keep the polymorphic-method based approach, you can
avoid type annotations in stat1#show an state2#show by writing
(this : #state).

But another way to simplify things is to switch to subtyping.
That is, just have
  method show : param -> unit
in class state, and change context to
  method show = state_#show (this :> param)

Note also that your definition of state as a recursive type will cause
problems later, if you try to finalize it in a class.

Here is a possibly simpler version of your code.

class type param =
 object 
 method name : string
 end

class type ['next] state =
 object
  method show: param -> unit
  method next: 'next
 end

class ['state] context s =
 object (this:'self)
 val name = "context"
 val state : _ #state = s 
 method state : 'state = state
 method name = name
 method show = state#show (this :> param)
 method run = {< state = state#next >}
 end

class state1 = object (this : _ #state)
 method show c = print_endline ("state1 of " ^ c#name)
 method next = new state2 
end
and state2 = object (this : _ #state)
 method show c = print_endline ("state2 of " ^ c#name) 
 method next = new state1
end;;

let c = new context (new state1) ;;
c#show;;
let c = c#run;;
c#show;;

Note that there is an intrinsic weakness to the object-oriented
approach in ocaml: state1 and state2 must actually be the same type,
since a method of context cannot return context with a different
parameter.

On the other hand, if you exactly know what a state should be from the
beginning, you can eliminate all type parameters.

class type param =
 object 
 method name : string
 end

class type state =
 object
  method show: param -> unit
  method next: state
 end

class context s =
 object (this)
 val name = "context"
 val state : state = s 
 method state = state
 method name = name
 method show = state#show (this :> param)
 method run = {< state = state#next >}
 end

class state1 = object (this : #state)
 method show c = print_endline ("state1 of " ^ c#name)
 method next = new state2
end
and state2 = object (this : #state)
 method show c = print_endline ("state2 of " ^ c#name) 
 method next = new state1
end;;

But then there is little point in using classes... records and
functions would do the job in a clearer way.

Jacques Garrigue


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

* Re: [Caml-list] state pattern...
  2005-06-28  0:54     ` Jacques Garrigue
@ 2005-06-28 12:24       ` Michael Wohlwend
  2005-06-28 13:20         ` Jacques Garrigue
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Wohlwend @ 2005-06-28 12:24 UTC (permalink / raw)
  To: caml-list, Jacques Garrigue

thanks for your reply, it's increasing my understanding of the object system, 
although there are some (or more... :-) open points:

In:
class ['state] context s =
 object (this:'self)
 ...
end

what are the reasons to give 'this' a type, and isn't 'self a type-variable? I 
thought it ('this') has the type of the class (= _context) ? I don't 
understand why and when it is needed to give the object a type.
The same with:
class state1 = object (this : _ #state) ...  end

I thought class state1 is a subtype (or implementing the class-type) #state, 
since the methods are the same. Why does it help to give the obejct a type?

thanks for your help, I would really like to understand the object system 
better. The state machine is surely better written using records and 
function; but this (supposed to be) little task is/was helping me indeed 
learning more of the class system. (And I hate it, not being able to solve a 
problem, which seems to be an easy one :-)

 cheers
 Michael


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

* Re: [Caml-list] state pattern...
  2005-06-28 12:24       ` Michael Wohlwend
@ 2005-06-28 13:20         ` Jacques Garrigue
  0 siblings, 0 replies; 7+ messages in thread
From: Jacques Garrigue @ 2005-06-28 13:20 UTC (permalink / raw)
  To: micha-1; +Cc: caml-list

From: Michael Wohlwend <micha-1@fantasymail.de>

> thanks for your reply, it's increasing my understanding of the object system, 
> although there are some (or more... :-) open points:
> 
> In:
> class ['state] context s =
>  object (this:'self)
>  ...
> end
> 
> what are the reasons to give 'this' a type, and isn't 'self a
> type-variable? I thought it ('this') has the type of the class (=
> _context) ?

You're correct. In this case, 'self will be bound to the type of the
class. This is useful if you want to write a type using it. But in the
code for context, this is not used, so ":'self" could be omitted.

> I don't understand why and when it is needed to give the
> object a type.
> The same with:
> class state1 = object (this : _ #state) ...  end
> 
> I thought class state1 is a subtype (or implementing the class-type) #state, 
> since the methods are the same. Why does it help to give the object
> a type?

Again you're correct. But here the type annotation forces all methods
of state1 to have the same type as in state. In practice, this avoids
annotating c in the method show. This works with polymorphic methods
too.

Cheers,

Jacques Garrigue


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

end of thread, other threads:[~2005-06-28 13:20 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-06-26 19:57 state pattern Michael Wohlwend
2005-06-26 22:13 ` [Caml-list] " james woodyatt
2005-06-26 22:45   ` Michael Wohlwend
2005-06-27 23:23   ` Michael Wohlwend
2005-06-28  0:54     ` Jacques Garrigue
2005-06-28 12:24       ` Michael Wohlwend
2005-06-28 13:20         ` Jacques Garrigue

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