Boost logo

Boost :

From: Andreas Huber (ah2003_at_[hidden])
Date: 2004-05-25 10:16:06


Johan Nilsson <johan.nilsson <at> esrange.ssc.se> writes:

> boost::fsm::static and boost::fsm::dynamic ?

Or boost::static_fsm and boost::dynamic_fsm...

[snip]
> Sorry, "rewriting" was entirely incorrect; I referred to modifying the
> source code when a reaction (correct terminology?) should result in a
> transition to a newly implemented state (i.e. one not originally defined).

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.

[snip]
> > > Exception: outer states should have some knowledge about inner states
> (they
> > > might be considered state-machines themselves).
> >
> > I don't see what that would buy you. I think it is a bad idea to have
> outer
> > states know exactly what inner states they contain. This would make it
> close
> > to impossible to spread machines over multiple translation units, which I
> > consider a key feature of my library.
>
> I didn't intend to imply that states should _exactly_ know their inner
> states (i.e actual types). I was thinking more in terms of the
> implementation of a superstate as an fsm itself (and, more specifically I
> guess, dynamic fsm:s).

Ok, but I still don't understand your question/suggestion/proposal. Could you
please expand?

[snip]
> > So you would still have objects for states but you'd create them when the
> > state machine is created, right?
>
> No, before.

When before? At program startup?

[snip]
> No, only if statically defined. I was thinking in runtime-terms again,
> perhaps:
>
> //
> // pseudo-code (no, I didn't think thoroughly before writing this)
> //
> from_state_id = fsm.add_state(<some-state>)
> to_state_id = fsm.add_state(<another-state>)
> fsm.add_transition(from_state_id, <on-event>, <event-result>, to_state_id)
> fsm.add_transition_to_self(from_state_id, <another-event>,
> <another-event-result>)

Yes, this is incompatible with static FSMs...

[snip]
> > I've never heard about such a state machine feature. UML has do-activities
> > that are associated with a certain state. When the state is left the do-
> > activity is aborted.
>
> I guess it's not in the formal definition of state machines. I'll try to
> give an example; suppose one state is responsible for updating the status of
> a remote entity via TCP when active; but the remote entity requires a
> periodic keep-alive so as not to close the connection

Why not create the thread in an outer state or even in the state machine
constructor and keep it alive for the whole lifetime of the state machine? If
the thread needs to be alive longer than a certain state does I would consider
it a design error to make it a member of the state.

[snip]
> > (consider a state needing to setup a TCP
> > > connection). This could be handled in the current fsm implentation (I
> > > believe) by keeping such things in the fsm or enclosing state - but
> there's
> > > that coupling again.
> >
> > You lost me here.
>
> 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.

> > > no socket creation errors; ... etc .. during runtime
> > > [basically the same as 3.2 above]. (aka "do or die").
> >
> > No problem either, just allocate your socket first thing in an outermost
> state
> > and never leave that state unless the state machine is terminated.
>
> Isn't that quite a restriction? I do like the 'context' stuff, but in a
> complex statemachine the context could get bloated with unrelated
> functionality.

No, quite to the contrary: It gives you the opportunity to give every object
exactly the lifetime it needs to have. If your object needs to live longer
than a particular state does, make it a member of one of its outer states. I
still fail to see what the problem with this approach is.

[snip]
> I just looked up the term do-activity and it seems to model the concept
> rather nicely.
>
> If yes, then you can already implement these with a thread
> that is
> > started in the entry action and cancelled (!) in the exit action of a
> > particular state.
>
> Again, that's quite a heavy-weight solution. How about implementing the
> do-activity with a worker thread in the fsm itself (requires cooperation
> from within the active state, of course).

Still, that functionality is orthogonal to what boost::fsm does. You can
easily implement this yourself without changing one line in boost fsm
(provided you have a threading lib supporting cancellation).

> > Huh? I guess I was dreaming when I wrote that. Where do I mention this? I
> > don't see any way how a dynamic FSM could be implemented in terms of
> > boost::fsm.
> >
>
> --- rationale excerpt ---
> Why not use a dynamically configurable FSM library for all state machines?
> ...
> It is for these reasons, that boost::fsm was built from ground up to not
> support dynamic configurability. However, this does not mean that it's
> impossible to dynamically shape a machine implemented with this library.
> ...
> --- end rationale excerpt ---
>
> Or do I misinterpret the meaning of the text?

Yes, you should have quoted the following sentences also:
<quote>
For example, guards can be used to make different transitions depending on
input only available at runtime. However, such layout changes will always be
limited to what can be foreseen before compilation.
<\quote>

I think the last sentence very clearly explains the difference between a
dynamically shaped static fsm and a fully dynamic fsm, does it not?

Regards,

Andreas


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