Re: [boost] New library in Vault: Msm (Meta State Machine)

Hi Andreas, First of all, thank you for taking the time for such a lengthy answer.
So IIUC then you think that transitions crossing state boundaries are bad practice and should be avoided at all costs?
Yes I do (not at any cost of course). Not only because it looks to me like a goto, but also because I feel it is a breach of encapsulation, for example, in the diagram, the "alarm-beeps" state is showing its implementation. It is also unclear to me if the entry method of "alarm-beeps" will be called.
OTOH, the transition triggered by x can only be made non-state-boundary-crossing by introducing a guard, which is IMO less
concise than allowing for the transition as shown in the chart.
This is a matter of taste. I personally prefer this as it reduces the coupling of the system.
As an aside, I don't see much of a connection of state-boundary crossing transitions with goto. Given your code in the C() function, any transition
could/would be implemented with goto?
What I mean is that if you imagined a transition processing as a function call, code using entry pseudo-states would in effect look like the code in the C() function where you could skip the initialization work done in the entry of C and B. It was not meant as real code but as illustration. Sorry if I didn't manage to make my point clear.
Given the examples in the Harel paper and the fact that the UML standard expressly allows them, I would encourage you to support them.
So does C++ support goto and breaching encapsulation, and it still doesn't make them desirable to me. Now, I thankfully take the feedback, and if confirmed, I will add the entry/exit states.
for the same reasons I don't detect value in seeing a composite state as a fully fledged state machine (as your framework seems to do). I know that the UML
has so-called submachines but they are really just simple composite states
with entry and exit points thrown in.
I admit the UML standard is not too clear in its description of submachines but states the goal clearly (UML Superstructure specification v2.1.2 p549), as: "Submachine state is a decomposition mechanism that allows factoring of common behaviors and their reuse". And this is a main design point for Msm. Submachines in Msm intend to be reusable blocks, like classes and functions. They have entry points (entry conditions and initial states), can be defined in different files and reused in different state machines. What defines a FSM with Msm is its transition table, not the inside of submachines. Submachines can be reused in different main state machines and the link between all is the transition table. Now, if the outside world knows the inside of the submachine, which would in turn know about the outside world, I'm afraid it'll be hard for submachines to be reused. However, your example and your point of view are very interesting as they force me to offer a better solution than the one I have (which would be in the init state to forward the events manually). Would the following compromise solution be acceptable to you? Like with deferred events, it would be possible to define automatic forwarding in a state (like the initial one) like this: typedef mpl::vector<T,T1,T2> forward_events; and at the end of the transition, these events would be resent (to the corresponding beep state as defined in the transition table). Like this, it is guaranteed that the entry methods are called, thus ensuring safe initialization and we would come close to an entry pseudostate. To explain better, I uploaded an image into the Vault. Regards and thank you for your time! Christophe

On Fri, 17 Oct 2008 11:15:48 -0500, Christophe Henry <christophe.j.henry@googlemail.com> wrote:
I admit the UML standard is not too clear in its description of submachines but states the goal clearly (UML Superstructurespecification v2.1.2 p549), as: "Submachine state is a decompositionmechanism that allows factoring of common behaviors and their reuse".
And this is a main design point for Msm. Submachines in Msm intend to be reusable blocks, like classes and functions. They have entrypoints (entry conditions and initial states), can be defined indifferent files and reused in different state machines. What definesa FSM with Msm is its transition table, not the inside of submachines. Submachines can be reused in different main state machines and thelink between all is the transition table.
FWIW, the above completely resonates with my experience of decomposing complex FSMs and is one of the reasons I'm excited about Msm. -- Aleksey Gurtovoy MetaCommunications Engineering

So IIUC then you think that transitions crossing state boundaries are bad practice and should be avoided at all costs?
Yes I do (not at any cost of course). Not only because it looks to me like a goto, but also because I feel it is a breach of encapsulation, for example, in the diagram, the "alarm-beeps" state is showing its implementation.
Right, which is why entry and exit points were introduced into the UML specs. This way, you avoid that a state has to show its implementation while still allowing state-boundary-crossing transitions. Whether you'd want to work with entry & exit points in the alarm-beeps case is a matter of taste. I personally wouldn't bother simply because it seems unlikely that it can be reused anywhere. The important point however is that entry and exit points are "just" abstraction mechanisms. Under the hood you still have a state-boundary-crossing transition.
It is also unclear to me if the entry method of "alarm-beeps" will be called.
Yes, it must be called, see below.
OTOH, the transition triggered by x can only be made non-state-boundary-crossing by introducing a guard, which is IMO less concise than allowing for the transition as shown in the chart.
This is a matter of taste. I personally prefer this as it reduces the coupling of the system.
To reach a definite verdict in this particular example we'd need to define first what coupling in a state machine actually means. To my knowledge, nobody has done that so far.
Given the examples in the Harel paper and the fact that the UML standard expressly allows them, I would encourage you to support them.
So does C++ support goto and breaching encapsulation, and it still doesn't make them desirable to me.
Given my first 3 paragraphs above, I hope it has become clear that a state-boundary-crossing transition combined with an entry/exit-point is *not* an encapsulation breach.
Now, I thankfully take the feedback, and if confirmed, I will add the entry/exit states.
Just to make sure we're not talking past each other: With "entry/exit states" I guess you mean "entry point pseudostate" and "exit point pseudostate" as defined in UML? If not please define.
for the same reasons I don't detect value in seeing a composite state as a fully fledged state machine (as your framework seems to do). I know that the UML has so-called submachines but they are really just simple composite states with entry and exit points thrown in.
I admit the UML standard is not too clear in its description of submachines but states the goal clearly (UML Superstructure specification v2.1.2 p549), as: "Submachine state is a decomposition mechanism that allows factoring of common behaviors and their reuse".
You have read the whole paragraph, right? I quote it here for clarity: <quote> A submachine state is semantically equivalent to a composite state. The regions of the submachine state machine are the regions of the composite state. The entry, exit, and behavior actions and internal transitions are defined as part of the state. Submachine state is a decomposition mechanism that allows factoring of common behaviors and their reuse. </quote> Note the first sentence. What is unclear here?
And this is a main design point for Msm. Submachines in Msm intend to be reusable blocks, like classes and functions. They have entry points (entry conditions and initial states),
I don't follow. Isn't it a fact that the current version of Msm only supports a single entry point for a composite state/submachine, namely the initial state?
Now, if the outside world knows the inside of the submachine, which would in turn know about the outside world, I'm afraid it'll be hard for submachines to be reused.
Exactly. However, IIUC, at the moment Msm only supports a single entry point and a single exit point, which IMO also makes reuse harder than necessary, see below.
However, your example and your point of view are very interesting as they force me to offer a better solution than the one I have (which would be in the init state to forward the events manually). Would the following compromise solution be acceptable to you? Like with deferred events, it would be possible to define automatic forwarding in a state (like the initial one) like this:
typedef mpl::vector<T,T1,T2> forward_events;
and at the end of the transition, these events would be resent (to the corresponding beep state as defined in the transition table). Like this, it is guaranteed that the entry methods are called, thus ensuring safe initialization and we would come close to an entry pseudostate.
Firstly, let's be clear that any reasonable semantics definition for FSMs (e.g. Harel, UML) absolutely requires that an entry action of a composite state/submachine is called when the composite state/submachine is entered and it doesn't matter at all how the state is entered (ordinary transition, state-boundary-crossing transition). The same goes for the exit action when the state is left. Secondly, IMO your approach with event forwarding makes matters more complicated than necessary, for at least two reasons (more problems might surface once you use the approach in practice): a) The events triggering transitions that enter a submachine (as defined by UML) by crossing the state boundary must be known inside the submachine. This undermines reusability, as you can't reuse the submachine in a different context where other events trigger the transitions. Sure you could pass the types of the events as template parameters, but you'd still need to mention the triggering events in two places. b) Internal events sometimes need to be posted inside transition actions. If the associated transition happens to be a state-boundary-crossing transition, then with your proposed approach such an event would need to be deferred until the forwarded event of the transition has been processed. To cut a long story short: I would encourage you to do either of the following: 1) Allow state-boundary-crossing transitions (without entry/exit points). Once you have these, entry- and exit-points are a no-brainer: An entry point is simply a member typedef in the type that defines the submachine. An exit-point can be supported just as easily by passing the destination state(s) as template parameters to the submachine. 2) Introduce entry & exit points as first-class concepts. Implementing a state-boundary-crossing transition would then become a three step process: a) define an entry/exit point, b) connect the point with an internal state, c) connect the point with an external state. In my (admittedly biased) view and from a purely conceptual standpoint (ignoring e.g. performance and other real-world stuff for the moment), option 1 is clearly superior as it gives the user complete freedom how to tackle his design problems. Option 2 would be acceptable, when it is clear that supporting 1) requires too many trade-offs. Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.
participants (3)
-
Aleksey Gurtovoy
-
Andreas Huber
-
Christophe Henry