Boost logo

Boost :

Subject: Re: [boost] [msm]exit pseudo state and event
From: Christophe Henry (christophe.j.henry_at_[hidden])
Date: 2011-07-01 12:55:19


> Hello,
>
> Boost.Msm supports the UML2.0 feature "exit pseudo state".
> Here is a description about exit pseudo state in the document.
>
>> exit_pseudo_state
>>
>> Basic type for exit pseudo states. Exit pseudo states are an
>> predefined exit from a submachine and connect two transitions.
>> The first argument is the name of the event which will be
>> "thrown" out of the exit point. This event does not need to
>> be the same as the one sent by the inner region but must be
>> convertible from it. The second argument is needed if you
>> want your state (and all others used in a concrete state machine)
>> to inherit a basic type for logging or providing a common behavior.
>>
>> template<class Event,class Base =
>> default_base_state, {
>> }
>> class SMPtrPolicy = no_sm_ptr>
>> exit_pseudo_state {
>> }
>
> Why the 1st template parameter "Event" is needed?

It is needed for implementation reasons. Actually it might not be needed if
I decided to hardcode an event (like "none" as you later suggest).

> Consider the attached diagram "11_ExitPointEvent.png".
>
> IMHO, the Exit2 is typical usecase of exit pseudo state.
> Outgoing transition from exit pseudo state shouldn't have
> any events and guards.
> The point is how to divide the concerns.
> When we design the Sm1, we can depend only State1,
> State1::Exit1, State1::Exit2 and State2.
> And we shouldn't depend on which event triggers the
> transition to pseudo exit state.
> It's State1's concern.

True. OTOH, letting a submachine decide which event is exiting this
submachine creates a constraint on the main state machine. The goal of the
implementation is to remove this constraint.

> To implement that, I pass the "none" as 1st template parameter.

It is acceptable to msm and probably in the spirit of the Standard.

> namespace msmf = boost::msm::front;
> struct Exit2:public msm::front::exit_pseudo_state<msmf::none> {};
> (See the attached file 11_ExitPointEvent.cpp)
>
> I think it is suitable for the default template parameter.

Maybe (see below).

> The example in the Boost.Msm tutorial document, the usage of
> exit pseudo state is similar as Exit1 in "11_ExitPointEvent.png".
>
> The behavior that I understand is below.
> In State1
> 1. Event1 is occurred,
> 2. Transition to Exit1.
> 3. Event1 is converted to Event2 (Exit1's template argument).
> In Sm1
> 4. Dispatch Event2.
> 5. Transition to State2.
> (Entry, Exit action is omitted)
>
> Is that right?

Yes.

> I'd like to know why such complicated mechanism is needed?
> Is the purpose to propagate the event parameter?

As implementer, I allow myself from time to time to ignore the standard
(implementer's privilege ;-) ) where I feel it forces unacceptable
constraints on me. This is such a case.
There are several reasons. One is as you noticed, not to lose the event type
and even more, data. If an event has some attributes, converting it to
"none" will lose them. Slicing and subtle bugs in waiting.

The second reason is this extra constraint. It is a constraint coming from
down in your design. This simply feels wrong to me. The implementation of
msm allows the writer of the main machine to have less constraints. He can
decide to write an event convertible from any other event, or to take over
only data from the inner event. Consider event6 from the tutorial. I could
write:

    struct event6
    {
        event6(){}
        template <class Event>
        event6(Event const& e)
       {
           some_id_ = e.id();
       }
       int some_id_;
    };

The dependency to the submachine is only a weak one.

The third reason is that we would have in our main machine a second-class
transition. No event, no guard. Which implies no possible transition
conflict resolution. What if I want to implement an "if/else" mechanism in
the main machine? Not possible. I will be forced to add a state as target of
this transition whose sole purpose would be to provide me with a set of
outgoing transitions implementing my "if/else". But without event data (as
we would only have "none"), I would not be able to implement every case and
I will be forced to resort to lesser solutions (like adding attributes to
the submachine to store event data).

This is a personal choice but these reasons matter to me more than the extra
complexity added by a template parameter.
If your taste is the Standard one, it is fine with me, just define "none" as
event parameter.

The next point to consider is whether to make "none" a default parameter.
One one hand, it would make the pseudo exit almost Standard-conform (if we
ignore the possible on_entry/on_exit handlers which are not foreseen by the
Standard), on the other hand, someone not knowing this finesse of the
Standard and providing no event parameter and a normal outer transition with
an event will be quite surprised to get no_transition handler calls.
I do not favor forcing bugs on msm users (which qualifies as a "complicated
mechanism") only to please the Standard.

> Thanks,
> Takatoshi

Regards,
Christophe

PS: I just realize this post would be a good addition to a Rationale section
;-)


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