Boost logo

Boost :

Subject: [boost] [MSM] Comparison with ad-hoc FSM implementation
From: Christophe Henry (christophe.j.henry_at_[hidden])
Date: 2009-12-09 05:56:51


Hi Phil,

>switch ((state<<8) | event) {
> case (Stopped<<8)|play: start_playback(); state=Playing; break;
> case (Stopped<<8)|open_close: open_drawer(); state=Open; break;
>etc. etc.

>The greatest advantage of this ad-hoc style is that it is readable
>by anyone who has even the most basic understanding of C++ without
>the need to learn a new library, and its exact behaviour is immediately
>evident. It is also likely to compile and run quickly.
>
>I have no doubt that MSM has many benefits compared to this. Perhaps
>it would be useful to spell them out?

The question is of course slighty provocative but still valid. The
answer will be quite long, sorry about that.

I won't say that your solution is not good. Actually if someone is
happy with such a solution, great for him. If you check the review
from Franz Alt, you'll see the source code generated by Rhapsody,
which is not very different from this one, the O(1) double-dispatch
excluded.
And it's at least way better than non-formal state machines which I
happen to see in production code again and again.
A state machine library, including MSM, is made for people who are not
happy with such an approach. I wrote MSM out of sheer frustration with
Statechart's inability to provide me with what I was looking for, and
out of admiration for the solution presented in the MPL book. I only
hoped that others felt like me and would like an alternative.
Concretely, what I was looking for:
- a descriptive, expressive and declarative state machine syntax.
- most of UML features which are hard to code with a switch/case dispatch.
- a library with the explicit goal of supporting a
Model-Driven-Development process
- enough speed so that it'd be hard to reject a state machine simply
on speed grounds (usual excuse).

Next, you wil ask me what UML features I deem so important that it
justifies a library.
My personal favorites (order by what I use most):
- events containing data. In your case, you are more or less forced to
choose between the O(1) (which you did) and forgo event data or the
O(n) (chosen by Rhapsody) at a speed cost. Metaprogramming techniques
allow us a O(1) with event data.
- actions/guards. Luckily, they are easy to implement in a switch/case.
- orthogonal regions. I often use them for error handling and they
greatly make the machine more readable by reducing the number of
transitions. Also hard to get with a switch/case.
- submachines (makes the code cleaner). Implementing them inside a
switch case is simply horrible. Soon, you need to hide them in
subclasses so we are already going in the direction of a library.
- flags. Will make the calling code easier
- exit points. Not my favorite, but always needed. Will quickly make
your switch/case implementation hard to follow.
- anonymous events. Hard to write with a switch/case dispatch. Luckily
for your case, not everybody likes them.
- history. Easy to implement in a switch/case (as long as you don't
need them event-dependent) but doesn't make your code any more
readable

Of course, like always, developers use only 20% of all UML features.
But it's never the same 20%, so what you need depends on your "coding"
style.
And if you want to implement all these features in a switch/case, your
code will quickly become terrible. You'll have to issue guidelines on
how to implement them, each developper will have to redo the same
again and again with the corresponding flow of bugs (what if I forget
a "break"? Uh oh) and low productivity (not even talking about
documentation).

Do we agree that this proves the need of a library?

The next valid question would be, why MSM?
It doesn't have to. If you're happy with Statechart or another library
and don't need the speed, it's really ok for me, I promise ;-)
MSM is for people who, like me, want a declarative syntax. People who
want to have a look at the transition table and see the whole
structure of a machine. Not as clearly as on a diagram but better than
just code. That's why there is a transition table, and that's why
there is eUML, to make it even clearer.
This will greatly help us developers communicate with domain experts
who will not understand code, but quite fast understand a state
machine (I tried an it works).

The second reason is the descriptive syntax of MSM. I wanted a library
which would help a Model-Driven-Development. I wanted a library
allowing us to switch from a graphical model to code and code to
model. And I wanted the mapping to be complete. The goal would be to,
at some point, never have to edit the code. I don't know how far I'll
push it but you can be sure that I will push it as far as I can. This
is where the functors added in eUML and the reusable states will help.

I hope I managed to answer your question.

Christophe


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk