Boost logo

Boost :

From: Andreas Huber (ahd6974-spamgroupstrap_at_[hidden])
Date: 2005-02-14 12:29:26


David Abrahams <dave <at> boost-consulting.com> writes:
>
> "Andreas Huber" <ahd6974-spamgroupstrap <at> yahoo.com> writes:
>
> > David Abrahams wrote:
> >> "Andreas Huber" <ahd6974-spamgroupstrap <at> yahoo.com> writes:
> >>
> >>> You very often encounter the situation that you need a variable that
> >>> is only used in a part of a state machine (i.e. only one state or a
> >>> few states need access to it). IMO, it is good design to confine the
> >>> lifetime of such a variable so that it will not even exist when the
> >>> machine does not happen to reside in the states that need access to
> >>> the variable. Even for a very tiny state machine like the StopWatch
> >>> in my tutorial it made sense to limit the lifetime of one variable.
> >>> See http://tinyurl.com/5q9hk (State-local storage) for details.
> >>
> >> But as I pointed out and -- you seem to agree -- that variable must
> >> often persist through several states to which it applies.
> >
> > Yes, often.
> >
> >> In that case, if you want the lifetime to change based on those
> >> states, you can't store the variable in the state object.
> >
> > Not in an innermost state, no. But you can simply store the variable in
> > an outer state that contains all the states that need to access the
> > variable.
>
> Can't we call that thing "the state's associated data object?"

You mean the variable?

> Calling it "the state" gives me the willies.

Huh? I don't see where I have called the variable a state, so my assumption
above must be wrong. I guess you lost me...

> > More often than not the outer state already exists for other
> > reasons (e.g. reactions that all inner states have in common). E.g. in
> > the StopWatch example, the Active state not only exists so that it can
> > store the elapsedTime_ member but also because there is a
> > self-transition that can be triggered when the machine is in either the
> > Stopped or Running states.
>
> Sorry, details please? Where is this example?

http://tinyurl.com/5q9hk (State-local storage)

> >>>> it doesn't match up with the domain abstraction of state
> >>>> machines.
> >>>
> >>> How do you come to that conclusion?
> >>
> >> I have never seen a formal description of the FSM abstraction that
> >> described states as carrying additional data inside them. Have you?
> >
> > No I haven't. To me this just follows naturally and at least a few
> > boost::fsm users seem to agree. I think it is awkward to store variables
> > in the state machine object, where they can be accessed from states that
> > are not supposed to access them. Of course this can be managed by the
> > framework as you suggest below, but the FSM class still becomes a change
> > hotspot. To me, such hotspots are an indication that there is something
> > wrong with the design. Moreover, parameterized states (aka submachines,
> > which are reusable FSM building blocks) are hard to implement without
> > state-local storage.
>
> Do you agree with Mr. Nasonov that outer states should be implemented
> as base classes of inner states?

Not as a general rule, no. However, sometimes it can be a valuable way of
implementing FSMs but this of course limits the value of variables in states,
see below.

> Because I don't see how the data
> lifetime issues work out if you do that. Transitioning from INNER1 to
> INNER2 still causes all the data members of OUTER to be destroyed,
> because the INNER1/2 instances have distinct OUTER sub-objects.

I guess you could copy the relevant portion of the old state object by the
means of giving each inner state a templated constructor (untested):

struct Active {};

struct Running : Active
{
  template< class Outer >
  Running( const Outer & outer ) : Active( outer ) {}
};

The Ctor is templated so that this continues to work even if Active stops
being an outermost state. But now I must admit that it's getting unwieldy ;-).

Anyway, your observation is correct: Without the workaround above, there is no
difference in lifetime no matter whether you store your variable in an
innermost state or any of its direct or indirect outer states. It gets
destructed with each transition. However, such variables would still be useful
for in-state reactions.

BTW, this lifetime issue is the primary reason why in boost::fsm an inner
state does not derive from its direct outer state.

Regards,

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

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