
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
[snip] 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.
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
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. 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.
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
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. 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):
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.