
Everyone,
I did just get around to give the MSM a first shot and I have say I am impressed at the neat design, the ease of use, "understandability", tutorial ... exceptional work. Really great and it helped me a great deal so far. So thanks a bunch for this teriffic addition to boost. That's the kind of stuff I love boost for.
Thanks :) Happy you like it.
There is one question however that puzzles me. How can / do I prevent state transistions when a transition function throws?
Most transition functions are defined like that:
void so_transition(event::Cause const &e) {
methodCausingAnException(); }
The tutorial only mentions this at the very end of the back-end docs and this is not clear to me. I have stuff inside my transitions that may throw and the example text mentiones other valid examples (like connect() logic). So what am I supposed to do here?
This?
void so_transition(event::Cause const &e) { try { methodCausingAnException(); } catch (const std::exception &sex) { return ??? } }
The type is void and I can't return anything that would prevent the transition. Or should I just let the exception pass? What is the correct way?
Suggestions are appreciated,
First of all, I have to give a word of caution. The UML Standard does not foresee exceptions and they don't mix well with the run-to-completion algorithm on which state machines rely. Try to avoid them if you can. This being said, exceptions happen in C++ ;-) By default, MSM catches them, then calls the exception_caught handler, which by default is: template <class FSM,class Event> void exception_caught (Event const&,FSM&,std::exception& ) { BOOST_ASSERT(false); } Like the no_transition handler, you can overwrite it with your own. When this is called, the transition is interrupted where it was and ceases processing. This leaves you in a not very desirable state because you have been interrupted somewhere in the guard/exit/action/entry chain. When this happens, I advise you to process to yourself an error event to handle this gracefully. For example: template <class FSM,class Event> void exception_caught (Event const&,FSM& fsm,std::exception& ) { fsm.process_event(ErrorConnection()); } But you still are somewhere in the middle of your transition. I think an elegant option would be to catch the exception in your action, then process yourself an error event. For example, using the more powerful functor front-end (providing you the fsm as parameter): struct so_transition { template <class EVT,class FSM,class SourceState,class TargetState> void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& ) { try { methodCausingAnException(); } catch (const std::exception &) { fsm.process_event(ErrorConnection()); } } }; You can prevent MSM from catching the exception by activating in your front end a switch: typedef int no_exception_thrown; Then, you get the exception thrown from your process_event call. In any case, the transition where the exception occurs is terminated and you don't need to terminate yourself.
Stephan
HTH, Christophe