
FSM Review - John Spalding - 2005/MAR/04 Contents - Overall impression. - my use case. - review manager's questions. ******************************* Overall Impression ******************************* I have been completly impressed by the FSM library, and recommend that it be immediately accepted into the Boost Libraries. I had been looking for a system that implemented hierarchical state machines, and never before found anything satisfactory. The ideas behind the Harel state chart had always seemed to me to have a place in standard software development. Prior to using FSM, I had read through another effort on C++ state machine development "Practical State Charts in C++", by Miro Samek, CMP Books, 2002, and found its methods unsatisfactory. I was impressed by Samek's advocacy of the utility of hierarchical state machines in software design. I am now using FSM for a modest practical project at my work, involving about 10 events and 10 states. FSM will replace a home brew non-hierarchical state machine. I like the ability to model hierarchical states and I also like the way FSM allows state networks to be constructed and modified quickly. => improvements - new user documentation <= I would add to the documentation a small section on trouble shooting the compile. When I started out, the fact that state machine connectivity was specified in templates caused me a bit of head scratching. My typical new-user mistakes resulted in lots of error messages. I would explicitly address this area, describing how connectivity errors cause compile time errors, for common state machine hook up errors. For example, if I change the "context" for just one state from the correct value to an incorrect value, I get over 90 lines of output. I think if you explicitly described a simple strategy for tracking down these connectivity problems, it would help the new user. ********************************************** Usability Evaluation - my modest use case. ********************************************** A distinguishing characteristic of this FSM library is its use of C++ templates to specify event/state connectivity. - we specify which events are handled or ignored when we are in a specified state. - we specify the sub-state network for the state machine. These are two separate connection operations. Both are specified by the class declaration for the state. A typical class template I used follows, in the example code. - the event handing connectivity is specified by the 3-rd argument to the fsm::simple_state<> template, an mpl::list of events. Simpler forms exist for the case that an event does not require special processing, however this general case is not complex. - the sub-state network is handled by the first two arguments to the fsm::simple_state<> template. The second argument simply names the "outer state", or containing state of this state. The outermost states of the finite state machine also have to instead name the controlling class, derived from fsm::state_machine. - In addition, I have provided an IFsmState<> template that implements a "GetState()" function that can be called by the state machine. I have used FSM to implement a modest sized state machine with about 10 events and 10 states. This particular state machine implements the high level application state of a data taking machine control application. In this application there are about 4 varieties of data taking. Using a common outer state Acquisition, containing the data taking states, allows me to write once the common code that causes data taking to stop. This application also monitors a significant number of conditions that require the system to take action when an abnormal condition (or hazard) occurs. This led me to have two outermost states, Hazard and NoHazard. When an abnormal condition is signalled, the hierarchy allows me to write once the code that stops data taking, and causes the system to enter the Hazard state. Bottom line, I found hierarchical state modeling to be very useful. I also found that FSM had answers for all the problems I encountered reducing the hiersrchical state machine to working code, in this relatively small example. The only "advanced" functions of FSM I utilized were state_cast<> and context<>. struct StIdle : IFsmState<StIdle>, fsm::simple_state< StIdle, StNoHazard, mpl::list< fsm::custom_reaction< EvSortEnter>, fsm::custom_reaction< EvCalEnter>, fsm::custom_reaction< EvTestEnter>, fsm::custom_reaction< EvTemplGenEnter> > > { StIdle(); ~StIdle(); fsm::result react(const EvSortEnter &); fsm::result react(const EvCalEnter &); fsm::result react(const EvTestEnter &); fsm::result react(const EvTemplGenEnter &); }; // Used for all states... struct IFsmStateQuerry { virtual const type_info & GetState() const = 0; }; // Used for all states... template<typename T> struct IFsmState : public IFsmStateQuerry { const type_info & GetState() const { return typeid(T); } }; class SystemFsm : public IFsmStateQuerry, public fsm::state_machine< SystemFsm, StNoHazard > { public: SystemFsm() { } // ... // Get state information. const type_info & GetState() const { // state_cast produces object in active state. // GetState returns type_info for that state. return state_cast< const IFsmStateQuerry & >().GetState(); } }; ***************************** Review manager's questions ***************************** What is your evaluation of the documentation? - I proposed adding a new user section, to help with compile time problems caused by state machine connect errors. - I also think the central role of the "context" parameter in simple_state<>, when specifying how to connect up all the states, could be stressed more, esp. for new users. What is your evaluation of the design? - I did not review the design implementation. - The FSM API is novel, due to template use, but I grew to like it. Are there parts of the implementation that duplicate parts of BOOST? - no, the entire FSM is novel. I did not evaluate performance bottlenecks, nor real-time aspects of usage. I did try to use the library for a practical library, and had lots of fun. (see my use case section) How much work did you put into the evaluation. - I have spent several days reviewing FSM, and have tracked it since I read about it on the boost list in 2004. - I have spent 2-3 days on the modest practical project. Domain Knowledge... - I am an "interested" user, but not an expert. I strongly believe FSM should be accepted into Boost.

Hi John
=> improvements - new user documentation <=
I would add to the documentation a small section on trouble shooting the compile. When I started out, the fact that state machine connectivity was specified in templates caused me a bit of head scratching. My typical new-user mistakes resulted in lots of error messages. I would explicitly address this area, describing how connectivity errors cause compile time errors, for common state machine hook up errors. For example, if I change the "context" for just one state from the correct value to an incorrect value, I get over 90 lines of output.
Hmmm, I'm wondering which version of the library you are/were using? A few months ago, I've added additional compile-time checks. While these do not reduce the length of the error messages, they should surely help you pinpoint the problem. In the library code, at the point of the error, there should always be a comment that describes the root cause of the problem. From there, you can follow the compilers backtrace until you reach a point in your code. Almost always, this first point in your code is also the point where the error is. You surely figured out the above yourself, I just wanted to ask you what version you used in the beginning and whether you have any examples of errors where there is no such comment in the library code. [snip]
I think if you explicitly described a simple strategy for tracking down these connectivity problems, it would help the new user.
Noted, I will do that. [snip]
- In addition, I have provided an IFsmState<> template that implements a "GetState()" function that can be called by the state machine.
I guess this machinery predates the introduction of state iteration (see state_machine::state_begin())? More on this below.
{
class SystemFsm : public IFsmStateQuerry, public fsm::state_machine< SystemFsm, StNoHazard public: SystemFsm() { } // ...
// Get state information. const type_info & GetState() const { // state_cast produces object in active state. // GetState returns type_info for that state. return state_cast< const IFsmStateQuerry & >().GetState(); } };
With the current version of the library this could be implemented as follows (requires the definition of BOOST_FSM_USE_NATIVE_RTTI in all translation units) ... // untested code class SystemFsm : public fsm::state_machine< SystemFsm, StNoHazard > { public: const type_info & GetState() const { if ( terminated() ) { throw std::bad_cast("Machine terminated"); } return typeid( *state_begin() ); } }; ... and makes IFsmState<> obsolete. [snip]
- I also think the central role of the "context" parameter in simple_state<>, when specifying how to connect up all the states, could be stressed more, esp. for new users.
Ok, noted. Thanks for your review! Best Regards, Andreas -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.
participants (2)
-
Andreas Huber
-
jdspalding@comcast.net