Boost logo

Boost Users :

From: Andreas Huber (ahd6974-spamgroupstrap_at_[hidden])
Date: 2005-07-15 10:02:15


[snip]
> Say for the PumpBase example, the designer of the main Fsm decides to allow
> customization for the Idle state and Running state. In the example
illustrated
> in the FAQ a MyRunning state (and inner states added to it) is defined and
the
> MyPump Fsm derives from PumpBase to specify a state transition to the new
> MyRunning state.
>
> Suppose now I want to add some inner states for the Idle state. I can define
a
> new MyIdle state but I cannot make it the initial state of MyPump since Idle
was
> specified as a template parameter in PumpBase and MyPump derives from
PumpBase.

Right. However, there's an easy workaround for this limitation: You
leave everything as in the FAQ item but you rename Idle, MyRunning and
Running to PreIdle, MyIdle and Idle respectively. You also *post*
EvStart inside PreIdle's constructor. When you initiate this machine,
there is an *immediate* transition to either Idle or MyIdle (depending
on the actual type of the machine). I'll soon update this FAQ item
accordingly.

> Let's put that aside and now let's suppose there's a third state in PumpBase
> Fsm: Stopped, and a state transition from Running to Stopped is triggered by
> event EvStop. and the following "point of customization" is defined in
PumpBase
>
> virtual sc::result react(Running& running, const EvStop &) const;
>
> To add inner states to Stopped I can define MyStopped and have MyPump
transition
> from Running to MyStopped. However in MyPump Running is replaced by
MyRunning,
> so I need to have my own react method to transit to MyStopped, and I'm not
even
> using the "point of customization" in PumpBase because it has a different
> signature. Up till now it looks like I'm defining a new Fsm to replace
PumpBase
> rather than customizing it.

Correct. In order to use this point of customization you will have to
transition back to a state defined in the base FSM, for example
PreStopped (can't think of a better name right now). PreStopped then
uses the technique I outlined above to transition to either Stopped or
MyStopped. A little awkward, I know, but it works quite well in
practice if there aren't many such points of customization.

> All this is fine if PumpBase has few states. Yet consider the case when 2
> developers work on PumpBase, one responsible for customizing the Running
state,
> the other for customizing the Stopped state. The developers should be able to
> work on the state machine without knowing each other. Yet as I've illustrated
> above, there can only be one MyPump class and whoever writes that class has
to
> be aware of the MyRunning and MyStopped class and write the react functions
> accordingly.

I'm not sure whether I understand 100% but it seems if you use the
technique above this shouldn't be a problem.

> btw, I think there's a typo in the FAQ code snippet. "sc::custom_reaction<
> EvStart >" should not be the third template argument for struct Idle.

Right. This is the old syntax. I forgot to transform the FAQ page to
the new syntax that is documented in the tutorial and the reference.

> > Maybe there's just a terminology misunderstanding but I don't see the
benefit
> > of the context object. In fact, the use of a context object here looks
like a
> > common antipattern, a "winnebago" object (stolen from Jeff Garland). You'll
> > find more on this here (search for the first occurrence of "heuristic" and
> > read what follows):
> >
> > http://lists.boost.org/MailArchives/boost/msg79540.php
>
> Yes it is an antipattern if the object requires modification everytime a new
> field is needed, but with a property map the new field can simply be inserted
> into the map.

That's one way to get around that problem, but it has a price: You lose
type-safety.

> Moreover, since a state class is destroyed after a state is
> exited, any state information stored within that state is lost.

Not if you group states inside outer states according to their need to
share variables. In the StopWatch example, the elapsedTime_ member
resides in the Active state exactly because it needs to persist over
Running <--> Stopped transitions. The Active state is only destroyed
(and with it the elapsedTime_ member) when you terminate the whole
machine or send an EvReset event to it.

> Information that
> needs to persist throughout the execution of the state machine has to be
stored
> in the state machine class,

Right. If you have variables that really need to live throughout the
lifetime of the whole FSM (including through initiate() and terminate()
operations) you definitely must put them into the FSM class itself.

> which in effect becomes the winnebago object.

That really depends on the design of the FSM. For flat FSMs you're
right, but one point of hierarchical FSM is that you logically group
states that share common "properties" into outer states. In traditional
FSMs these "properties" were reactions only, Boost.Statechart enables
you to also group states accoring to their need to share variables. The
good thing is: States that share variables almost always also share
reactions and vice versa. E.g. in the StopWatch example, Stopped and
Running share elapsedTime_ as well as the transition triggered by
EvReset.

> p.s. thanks for showing me how to post on this list, I kept looking in the
> gmane.org site for instructions...

I was under the impression that unregistered people get email that
tells them how to register. This is obviously not the case so I really
should have told you that right in the beginning. Sorry.

HTH & Regards,

--
Andreas Huber
When replying by private email, please remove the words spam and trap
from the address shown in the header.

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net