Boost logo

Boost Users :

From: Andreas Huber (ahd6974-spamgroupstrap_at_[hidden])
Date: 2006-05-02 17:31:50


Tim Milward wrote:
[snip]
> Unfortunately I have no practical experience of using state charts
> yet, (I have done a lot of research/reading/designing), so can't
> answer your question. I want to use simple HSMs to control the
> threads in a GUI application (a more complex version of the Dining
> Philosophers Problem essentially).
>
> In my designs I very often use a composite state as the source for a
> transition, simply to avoid repetition (- avoid lots of transition
> lines from each sub-state on my diagrams). However the behavior I
> want is exactly the same as if I'd sourced the transition explicitly
> from each sub state.

Right.

> That is, I explicitly don't want the entry and
> exit actions of the composite to be called.

After doing some digging in the UML specs, it seems that a transition
can only be local when the destination state is a direct or indirect
inner (nested) state of the origin state. I see that this can be useful
sometimes but I still think that such transitions are relatively rare.

> That is perhaps why UML
> added local transitions - not for performance reasons, but for
> behavioral flexibility and expressivity.

Ok so far, local transitions can simplify a statechart under certain
circumstances...

> If you only model external
> transitions and want to use entry/exit actions you've essentially
> lost much the power of HSM's to represent FSM's more efficiently.

I don't follow. As I mentioned before, you can always simulate an
internal transition with an external one. The only thing you have to do
is to add one state:

<code>
#include <boost/statechart/event.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/transition.hpp>

namespace sc = boost::statechart;

struct E0 : sc::event< E0 > {};

struct S0;
struct Machine : sc::state_machine< Machine, S0 > {};

struct Intermediate;
struct S0 : sc::simple_state< S0, Machine, Intermediate >
{
  // Ctor & dtor as needed
};

  struct S00;
  struct Intermediate : sc::simple_state< Intermediate, S0, S00 >
  {
    // No ctor & dtor!
    typedef sc::transition< E0, S00 > reactions; // *** here ***
  };

    struct S00 : sc::simple_state< S00, Intermediate > {};

int main()
{
  Machine m;
  m.initiate();
  m.process_event(E0());
  return 0;
}
</code>

Now S0 has exactly one inner state, Intermediate, which in turn contains
all the states that were nested inside S0 before. If you want to add a
local transition to S0, you don't add it to S0::reactions typedef but to
the Intermediate::reactions typedef. If that reaction is triggered, any
currently active innermost state is exited, then Intermediate is exited
& entered and finally S00 is entered. S0 is never left, of course. The
only disadvantage I see with this pattern is that Intermediate is
destructed & constructed unnecessarily. Otherwise everything behaves as
if that transition was a local transition of S0.

>>> Tests with deep history produce a static assertion if you attempt to
>>> transition to history of a containing state. UML 2.0 explicitly
>>> permits this.
>>
>>
>> I disallowed such transitions because they don't seem to make sense
>> and there was no indication that they are allowed under UML 1.5.
>> IIUC, such a transition would simply leave & reenter the current
>> state, right? If so, what good is history for when the same effect
>> can be achieved by simply giving the state a normal transition to
>> itself?
>
> Giving a state a normal transition to itself would invoke it's
> entry/exit actions, or if modeled as an internal transition (in-state
> reaction) do none. Transitioning to deep history (of a containing
> state) should (in my opinion) invoke the entry/exit actions all the
> way back up to (but not including) the state containing the history.

Ok, that makes sense. From your example I assumed that you meant to
transition back to S00. But you had the more general case in mind where
you transition to history of an *indirect* outer state. This would of
course exit not just the innermost state but also an arbitrary number of
its outer states (and reenter them automatically afterwards).

> So as you can see I was interested in notationally efficient ways to
> invoke chains of entry/exit actions back up the hierarchy. The other
> thing to note is that this sort of transition to history technically
> doesn't require any extra storage of the deep history since it is
> just the current state (the composite state might not need to be
> parameterised with has_deep_history).

Right, but due to the way history is currently implemented an extension
allowing such transitions would most probably still require
has_deep_history.

>> Thanks for the feedback!
>
> Hope that all makes sense.

It does:
1. The modification in the history case should be trivial and
non-breaking, I guess I should be able to come up with a beta before
next Sunday. Would you be willing to test it?
2. I'm unsure what's the best approach in the local transition case.
Modifying the current behavior is out of the question for reasons of
backwards-compatibility. One option is to introduce sc::local_transition
and sc::simple_state::transit_locally() but I'm not sure whether that
would be such a good idea as it adds yet another way of expressing
something that can easily be achieved with little additional work.

Whatever modifications there will be, none of them will make it into
1.34, as we're already in the feature-freeze state. However, I'll add a
FAQ item that explains how local transitions can be implemented with
external ones.

> If I do use HSMs for my app, I think I'll
> use boost/statechart, and for now avoid entry/exit actions.

I would advise you not to avoid entry/exit actions. I believe doing so
would clutter your state machines much more than using the local
transition workaround I outlined above. I would be interesting to hear
some real-world experience in this case.

HTH,

-- 
Andreas Huber
When replying by private email, please remove the words spam and trap
from the address shown in the header.

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net