
Andreas Huber wrote:
Robert Bell wrote:
Here's one argument in favor of entry()/exit() over constructor/destructor. If you use constructors/destructors, your hands will be tied if someday you want to change your mind about the implementation of state entry and exit constructing and destructing states (a couple of alternatives have been discussed here, such as constructing states when they're entered but not destroying them when they're exited). If instead you implement entry and exit with entry() and exit() member functions, it doesn't matter if the states are constructed and destructed as they are now, constructed at entry point and destroyed at machine destruction time, or constructed all at once at machine construction time.
I don't have any idea if this flexibility is important or not, but if I was implementing fsm, I'd consider it.
Believe me, I *am* considering it. I even started dreaming about it :-).
That happens to me sometimes too. Sometimes I think it's cool. Other times I think it means I need a vacation. ;-)
However, no matter from what angle I start to think this through I always end up with the same bad feeling. If we introduce entry()/exit() for the reasons you give (more flexibility for optimization?)
More flexibility to change the implementation, for any reason (not necessarily optimization). By using constructors and destructors for entry and exit, you're telling users that fsm guarantess that States will be constructed and destroyed at specific times, which means that for all time fsm must provide those guarantees.
this essentially means to tell the users that they must not under any circumstances rely on when exactly constructors and destructors of state objects are called.
Keep in mind that it's entirely possible that I'm missign something. That said, they can't rely on when exactly constructors and destructors are called today.
Even worse, they must not even rely on how many times state ctors/dtors are called.
They can't rely on the number of times they're called now.
Today they might be called exactly as often as entry()/exit() but tomorrow they might be called only exactly once.
None of these issues having to do with when and how many times constructors and destructors are called sound bad to me; why would anyone care?
This means that most non-POD data members of states need to be created on the heap, as you otherwise wouldn't have a chance to create them inside entry() and destroy them inside exit(). And believe me, you definitely need to do that when you design non-trivial FSMs. Therefore, to me entry()/exit() means falling at least halfway back into medieval times where you always had to explictly call constructors and destructors yourself (Turbo Pascal).
I don't quite see it this way myself, but in any event, this is a concern for the implementer of fsm, not a user of fsm.
Please have a look at the StopWatch example and imagine the additional complexity introduced with entry()/exit() (and ctors/dtors called at unspecified times). I only want to go there if there are compelling reasons: - I believe that boost::fsm is already reasonably fast (and there is still some potential for optimization). Nobody who is actually using it has ever complained that it is too slow. Someone has even reported that it performs "very well".
I'm not so concerned about performance; if the interfaces are reasonably clean, it can always be optimized later.
- Nobody has so far presented hard technical facts that support the view that mapping entry/exit to ctor/dtor is wrong. To the contrary, I think I have almost proved in my discussion with Dave that exit actions must not fail and that you *can* recover from failing entry actions.
I'm not so sure there _are_ hard technical facts; there are just two different interface choices, each with different tradeoffs. I'm sure you've thought this out more than I have. I'm just coming from a gut-level reaction I have to linking entry/exit to construction/destruction. It just feels weird. For example, if entry and exit actions are things a state "does", then I'd expect them to be overridable; constructors and destructors can't be overridden. (In the past, when I've implemented state machines I've made Action a separate class; that way, Actions are attached to States, which makes it easier to reuse Actions in different States.) Don't take this as me saying you're doing it wrong or that fsm is ill-designed or anything like that. I just wanted to raise a point I have not yet seen raised, and as I said, you've obviously spent a lot more time working on this than I. I don't quite understand the objection to entry() and exit() member functions, but then again I don't have to understand it for fsm to proceed. Bob