|
Boost : |
From: Johan Nilsson (johan.nilsson_at_[hidden])
Date: 2004-05-26 05:56:08
"Andreas Huber" <ah2003_at_[hidden]> wrote in message
news:loom.20040526T100736-389_at_post.gmane.org...
> Johan Nilsson <johan.nilsson <at> esrange.ssc.se> writes:
>
> > > I guess we agree that you have to modify some code somewhere to
achieve
> > this
> > > behavior change. What's so bad about changing the code of the state
where
> > the
> > > new transition originates? I think this is superior to having a global
> > > transition table. Such a global table inevitably becomes a change
hotspot
> > in
> > > large FSMs and leads to frequent recompilations.
> > >
> >
> > Are we convinced that the only thing we're discussing now is static
FSMs? If
> > so, you are correct and I believe you've made a correct design decision
in
> > this particular respect.
>
> Yes, I am ;-). Seriously, I hope I have convinced you that we need two
> libraries: One for static FSMs and one for dynamic FSMs. I don't have
enough
> domain-knowledge to implement a dynamic FSM, so I can't really discuss
this
> with you without making assumptions that might well be false.
>
To be honest, when it comes to details I probably haven't either.
> > > Ok, but I still don't understand your question/suggestion/proposal.
Could
> > you
> > > please expand?
> >
> > It's neither; we're comparing apples and pears (well, that might be a
> > swedish idiom only .
> >
> > If a static FSM would have complete control over all transitions,
analogous
> > to the dynamic example I provided below, the static FSM would need to
know
> > all inner states. If a dynamic FSM would have complete control over all
> > transition it doesn't need to know the exact type of all inner states.
Am I
> > correct?
>
> Yes, I believe that is correct.
>
> [snip]
> > > > I just meant that the state is dependent on its "container" to
maintain
> > > > non-volatile data.
> > >
> > > Yes, what's so bad about that? An inner state always depends on the
> > behavior
> > > implemented by its outer state. Just like a derived class always
depends
> > on
> > > the implementation of its base class.
> >
> > For me, an inner state "is-not-a" outer state (regardless of the name
> > 'superstate' in the UML docs).
>
> Well, I think you have the wrong model of inner and outer states then.
Actually, it's more of a gut feeling.
> The
> correspondence between subclasses and inner states is really quite
remarkable:
> - The sequence of base and derived class constructor calls is the same as
the
> outer and inner state entry sequence
For the inital inner state, yes.
> - The sequence of destructor calls is the same as the exit sequence
In a way, yes. But the exit for the inital inner state is unlikely to be
immediately followed by the exit for the outer state (unless the initial
state's also the last inner state).
> - Inner states sometimes define an in-state reaction for an event that an
> outer state also has a reaction for and delegate to the outer state
reaction
> after doing some stuff internally. Derived and base classes do exactly the
> same through virtual functions.
True.
> - The LSP must hold for an outer state and all its inner states (see Miro
> Samek's articles in CUJ last summer).
I did read them; I'll have to re-read and get back on that. That implies
that all inner states must implement the (event handling) interface in the
same way as the outer state?
>
> > The outer state <-> inner state relation
> > feels more analogous to an association (or perhaps an aggregation). So
the
> > comparison to base and derived feels a bit out of hand. That's why I
don't
> > like the dependency on the "container". Two way associations generally
bring
> > with them too much coupling, IMHO.
>
> The only sort of two-way association exists between an outer state and its
> inner *initial* state. Even there it is not exactly two-way because the
inner
> initial state is an incomplete type when the outer state is defined.
> The outer state does not have any knowledge of any of its other inner
states.
>
> > Let me make an alternate suggestion: The states needing 'persistent'
data
> > (or functionality, such in the admittedly convoluted TCP example above)
> > would tell the state machine to maintain a special context object for
them -
> > for the entire lifetime of the FSM. This context object could be of any
> > class -> but should _not_ be the fsm itself or an outer state.
>
> Why not?
That should read "... should _not_ _have_ to be the fsm ..."
>
> > The context
> > object could inherit from a specific base just so that the fsm could
store
> > them conveniently. The type of the context object could be specified as
a
> > template parameter to the e.g. simple_state<> template. I'll try to
outline
> > an example, just to give you an idea (I won't consider the exact steps
> > needed to actually implement this):
> >
> > namespace fsm { struct no_context : fsm::context<no_context>{}; }
> >
> > struct my_state_context : public fsm::context<my_state_context, ...>
> > {
> > };
> >
> > struct my_state
> > : public fsm::simple_state<
> > my_state, ...,
> > my_state_context /* defaults to fsm::no_context */
> > >
> > {
> > };
> >
> > Access to the context should be made easy by providing the 'context()'
> > method in simple state, now returning a reference to the FSMs only
instance
> > of the context -> implemented in simple_state. The 'context' method
should
> > be unavailable if the context template argument equals no_context;
perhaps
> > doable through PTS.
> >
> > What would also be needed is the ability for several (closely related)
> > states to share the same context, but _still_ without the need for the
> > context to be the outer state or fsm - needs some consideration on how
to
> > implement this.
>
> That is all very interesting but I still don't get why putting your
objects
> into such a context container is better than putting your object in outer
> states or the state_machine subclass itself?
>
"That is all very interesting" sounds like you're fed up with this
discussion ... for me it boils down to a cleaner separation of the concepts
and looser restrictions on how 'context' is implemented; but let me put it
this way: what's so wrong about it?
> > As you see I really haven't concrete examples on how to implement this -
but
> > given this or similar implementation I could leave out the requirements
for
> > the actual state objects to remain live for the lifetime of the FSM
itself.
> > Now I could even make the context object an "active" object (i.e. run by
a
> > private thread).
>
> As I have already pointed out: I don't see why this should not be possible
> with boost::fsm as it is now. If your really need that thread to outlive
all
> your states then make the thread object a member of the state_machine
subclass.
>
True. Same as above holds here.
> > We'd still have the benefits of your basic FSM design; we'd have looser
> > coupling between outer, inner states and the FSM.
>
> No, we wouldn't. Inner states will always need to directly know their
outer
> states, there's no way around that (e.g. see the StopWatch example, where
an
> inner state accesses its outer state).
Got me there.
// Johan
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk