
https://sourceforge.net/project/shownotes.php?release_id=303009 This package has been tested on gcc 3.4 and linux-intel 8.0. Two kinds of overload sets are currently implemented: natural sets and range sets, that is, overloads::set<X> and overloads::set<X, mpl::range_c<int,1,3>
where X is (I call its concept OverloadsHolder, feel free to suggest better name):
struct X { void operator()(overloads::id<1>, int, char) const; // void(int,char) bool operator()(overloads::id<2>, long) const; // bool(long) }; mpl::end for natural set is not constant time but fast. The following MPL algorithms work: - has_key - order - find - size - empty - equal

Jonathan Turkanis wrote:
See for example fsm.cpp here: http://aspn.activestate.com/ASPN/Mail/Message/boost/2185183 or http://aspn.activestate.com/ASPN/Mail/Message/2483684 Unfortunately, there is no documentation yet. I hope MPL interface can help understanding it. Basically, you turn *definition* defined below into MPL Associative Sequence with simple typedef overloads::set<definition>. It will behave similar to mpl::set<int(int,int), float(int,float)>. Note that without typeof deref can't be defined (workaround exists). struct definition { int operator()(id<1> , int a, int b) const { return a + b; } float operator()(id<2> , int a, float b) const { return a + b; } }; _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Alexander Nasonov" <alnsn@yandex.ru> writes:
Alexander, If you want to convince people that your idea is useful it would be a good idea to make it easier for them to understand why. While I understand everything you've written above, I still don't know why I'd want this, and I'm not prepared to reverse-engineer an example FSM implementation to find out. -- Dave Abrahams Boost Consulting www.boost-consulting.com

-- David Abrahams wrote:
I don't know what do you mean exactly but I'm not yet going to convince people to use it because I'm in the middle of switching it from old interface to MPL set style. This version is a result of our discussion with Aleksey ("overloads: request for discussion" thread) and my message mainly directed to him. Sorry, that I didn't say that. If you mean that someone isn't convinced to adopt MPL algorithms for overloads or whatever else, let me know. -- Alexander Nasonov

Alexander Nasonov wrote:
What I would like to know is why you want to represent overload sets as compile-time collections: what sort of computations can you do with them in practice? I'm not expressing any scepticism that it's useful, I just want more information. Jonathan

Jonathan, /* I'm replying to you privately because I don't have access to my private * mailbox from work and apparently I don't want to publish my business * address on internet. As soon as I get home I'll post it to boost list. */ Jonathan Turkanis wrote:
Ok. Using state machine as an example: struct Fsm { Running operator()( id<1>, Passive, EvActivate ) const; Stopped operator()( id<2>, Running, EvStartStop ) const; Running operator()( id<3>, Stopped, EvStartStop ) const; Stopped operator()( id<4>, Active, EvReset ) const; // ... }; Every call operator has such pattern: NewState operator()(id<N>, State, Event) const; and represents a transition from a state State to a state NewState caused by event Event. Transition logic is defined in the call operator body. If you were using MPL containers you would need to implement the logic in separate functions and pass them along the lines of metainformation about FSM: // 1. Runtime part of information about transitions: Running activate(Passive,EvActivate); Stopped stop(Running,EvStartStop); Running start(Stopped,EvStartStop); Stopped reset(Active,EvReset); // 2. Compile-time part of information about transitions: typedef mpl::vector< transition<Running(Passive,EvActivate), &activate> , transition<Stopped(Running,EvStartStop), &stop> , transition<Running(Stopped,EvStartStop),&start> , transition<Stopped(Active,EvReset),&reset> > transitions; // 3. FSM generator: fsm<transitions,Passive> m; // initial state is Passive // 4. Go m.processEvent(EvActivate()); // ... Most interesing part here is FSM generator. Using the power of MPL and type_traits, it gets states out of transitions, allocates storage for them and generates transition table. Additionally, it could take into account inheritance relashionship between states to allow superstates/substates or it could treat void return type as no transition (action only) or it could discard transitions under certain circumstances or it could turn thrown exception into event and process it or ... A lot of interesting things are possible, thanks to MPL and other boost libraries :) My library is supposed to do same things. The difference is that step 1 and 2 are now not separated and you don't have to scroll up and down to make sure both parts are in sync. // 1. Runtime part of information about transitions is in Fsm's body // 2. Compile-time part of information about transitions is overloads::set<Fsm> struct Fsm { Running operator()( id<1>, Passive, EvActivate ) const; Stopped operator()( id<2>, Running, EvStartStop ) const; Running operator()( id<3>, Stopped, EvStartStop ) const; Stopped operator()( id<4>, Active, EvReset ) const; // ... }; // 3. FSM generator: fsm<Fsm,Passive> m; // initial state is Passive // 4. Go m.processEvent(EvActivate()); // ... Hope this helps, -- Alexander Nasonov

[I'm sending this again because the first version never showed up] Alexander Nasonov wrote:
Thanks, Alexander. I'm starting to understand now. Sorry I'm so slow.
I assume you're using id<..>'s to distinguish signatures even if they agree at every other position. My initial guess is that operator()'s with the same id<..> would correspond to functions having the same name. But then I see that each operator() seems to have a unique id<..>, which make me wonder where the overloading is.
Okay, I think I understand this example. I'm not so sure I see how, or if, this relates to overload resolution. In addition to the associative sequence operators, I would expect to have a metafunction that takes an argument list and determines which overload is called. Best Regards, Jonathan

Jonathan Turkanis wrote:
All ids are unique. This is how I can deduce a signature of every function without ambiguity. Of course, these ids change original overloads relation between functions but you can "bring it back" at call time: Fsm fsm; fsm(enable_all(), Passive(), EvActivate()); ^^^^^^^^^^^^ enable_all is not yet in tarball but it's very simple. You just make sure every id<N> has a constructor that accept enable_all.
Okay, I think I understand this example.
Hmm, I'm not sure I can implemenent such metafunction because of complexity of C++ rules. I have to look at details. -- Alexander _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Alexander Nasonov wrote:
Why is it called an overload set, then? Because all the functions are overloads of operator()?
I'm not really asking for you to provide this metafunction; I'm mostly trying to figure out what your implementation of overload sets has to do with the overload sets described in the standard. Jonathan

"Alexander Nasonov" <alnsn@yandex.ru> writes:
It's not directly relevant to your overloads component, but I'm very curious as to why you want to use _types_ to represent states. It seems counter-productive because of course types are static, and states are, well, stateful. Don't you end up wasting time and code translating between states and types? -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
That's possible. If your automata is essentially value-based (for example, FSM for searching subsrings in a string) then it's better to use something else. But, in a modern world, type identity plays an important role too. For example, if someone is developing FSM silimar to mine where each event has additional params (eg, EvActive may have priority), what would he/she prefer, to invent his/her own protocol to transmit event code and event specific params or to use existing technology like CORBA and to send objects? PS Mine code is implementation of UML diagram from boost::fsm tutorial by Andreas Huber: http://boost-sandbox.sourceforge.net/libs/fsm/doc/tutorial.html -- Alexander

I wrote:
Oopps, I mixed states and events up. I answer again. David Abrahams wrote:
That's not exactly true. States are _types_ only at compile-time. At runtime, they are objects passed to correspondent call operator. Objects may be stateful. struct Running { /* stateful */ }; struct Stopped { /* stateful */ }; Fsm fsm; Passive initial; Running r = fsm(enable_all(), initial, EvActivate()); Stopped s = fsm(enable_all(), r, EvStartStop()); r = fsm(enable_all(), s, EvStartStop()); s = fsm(enable_all(), r, EvReset()); -- Alexander

"Alexander Nasonov" <alnsn@yandex.ru> writes:
Even more confusing; now you need a dynamic allocation to represent and change the current state of the machine. I suppose you could use variant, but I never understood why people want to put state _inside_ of states -- it doesn't match up with the domain abstraction of state machines. The state's identity should be enough. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Even more confusing; now you need a dynamic allocation Why I need it?
There are two kinds of state: state of machine and class state. They're from different domains. Suppose Running state has m_speed member. Is it worth adding this member to the state identity? PS: We are ahead of time, boost::fsm review is scheduled on Feb 21 :) -- Alexander

"Alexander Nasonov" <alnsn@yandex.ru> writes:
I am assuming states come and go when the state of the machine changes. I suppose you can just keep a separate object of each state type alive continuously...
...in that case states _do_ come and go.
What is "class state?" Can you describe its domain? What are the principle abstractions in that domain?
Suppose Running state has m_speed member. Is it worth adding this member to the state identity?
Here you're arguing from a position that assumes states should have state, but that's the assumption I'm challenging. If I try to map what you're describing onto the state machine designs that we did for "C++ Template Metaprogramming" (and that I posted here), I could achieve something similar by simply putting storage for auxilliary data (like speed) in a data member of the derived FSM class. While I have to admit that your particular example seems to naturally call for associating that auxilliary data directly with the state class, that model doesn't generalize well AFAICT. There could be auxilliary data that's needed -- persistently -- for more than one state.
PS: We are ahead of time, boost::fsm review is scheduled on Feb 21 :)
:) -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
The man who invented examples is the greatest inventor of all time! After looking at mpl example I understand what do you mean. My code can be rewriten to support your style. You could typedef Running as state<0>, Stopped as state<1> and so on. The framework could find out that all state<N> are stateless (what a mess! :) and left out storage generation for them. I wonder when and why you need these numbers? Not for passing to switch statement, I hope? I suppose, you use them to check for a particular state of set of states like whether FSM is in final state(s) or not. If you do so, I do so as well.
Agree.

"Alexander Nasonov" <alnsn@yandex.ru> writes:
Okay.
Good.
My code can be rewriten to support your style. You could typedef Running as state<0>, Stopped as state<1> and so on.
I'll ask again: what is the point of using types for states?
You have to give the state some runtime-mutable representation, and numbers work very well as explained in the book.
Not for passing to switch statement, I hope?
It depends on the dispatching scheme you choose, but sure, why not a "switch statement?" The book's example generates the equivalent of a switch for each event type, using a cascade of inlined "if" statements. On on the CD there should be a version that does an O(1) lookup of a transition function in a linear table... oops, it didn't make it onto the CD. I've posted it here in the past, but it's attached again. I'm not convinced that it's faster to do it that way, though, for the typical state machine.
I suppose, you use them to check for a particular state of set of states like whether FSM is in final state(s) or not.
I'm sorry, "state of set of states?" I don't understand.
If you do so, I do so as well.
I don't know if I do so, yet ;-) -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams <dave@boost-consulting.com> writes:
oops, it didn't make it onto the CD. I've posted it here in the past, but it's attached again.
Oops again! Here it is: -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
I'll ask again: what is the point of using types for states?
You can't easily emulate is-a relationship with numbers. With classes you just derive one class from another. My example demonstrates this technique.
I don't know if I do so, yet ;-)
I mean I _can_ do so but switching to mpl concept doesn't go smoothly. Currently, I'm trying to understand why size of mpl::set<id<1>, id<2> > is 2 while distance between begin and end is one? -- Alexander

"Alexander Nasonov" <alnsn@yandex.ru> writes:
Okay, but what's the value of modeling an is-a relationship between states? In a FSM, states are distinct. One state is-not-a nother state.
My example demonstrates this technique.
AFAICT it seems to be a way of grouping states, or perhaps of emulating substates, so you can avoid writing the transitions that a group of states has in common (?)
I'm lost, sorry. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"Alexander Nasonov" <alnsn@yandex.ru> writes:
Sorry, I don't understand the meaning of "at modelling state." Oh, you mean "at modelling stage?"
So it's just a way of classifying states with common properties?
That's a clever approach to dealing with substates. I'm not sure it works for every case, but then, the details of how substates are supposed to work have always eluded me. I still don't see how you can keep associated data stored in the Active base sub-object alive across all the other active states, at least not without copying it. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
So it's just a way of classifying states with common properties? Yes.
I'm not quite sure my approach works well with substates.
Transition is copying. It is implied by transition pattern: NewState operator()(id, State, Event) const; ^^^^^^^^ new state is returned by value -- Alexander

David Abrahams <dave@boost-consulting.com> writes:
"Alexander Nasonov" <alnsn@yandex.ru> writes:
David Abrahams wrote:
What is "class state?" Can you describe its domain? What are the principle abstractions in that domain?
Sorry, I meant "principal abstractions." -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
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.
it doesn't match up with the domain abstraction of state machines.
How do you come to that conclusion?
The state's identity should be enough.
It is sometimes enough for small simple machines but not almost never for large complex ones. Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

"Andreas Huber" <ahd6974-spamgroupstrap@yahoo.com> writes:
But as I pointed out and -- you seem to agree -- that variable must often persist through several states to which it applies. In that case, if you want the lifetime to change based on those states, you can't store the variable in the state object. boost::optional in the state machine itself is the proper generalization of the idea.
I have never seen a formal description of the FSM abstraction that described states as carrying additional data inside them. Have you?
I believe that auxilliary data is sometimes needed, but I don't believe it's ever needed *in the state*. A framework that managed auxilliary state data might accept a a structure like this: mpl::vector< // speed applies to the "running" state aux_data<&player::speed, running> // title applies to the "stopped" and "paused" states , aux_data<&player::title, stopped, paused>
where speed and title are boost::optional objects that are automatically cleared by the state machine framework upon leaving the states listed with them. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Yes, often.
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. 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.
boost::optional in the state machine itself is the proper generalization of the idea.
It makes things global that should rather be left local. Below, as a counter-measure, you devise a system that does away with one aspect of the globality (the lifetime). But, other negative aspects of the globality remain, i.e. you still have to change the FSM class when you want to introduce a new variable or change an existing one.
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.
As outlined above, I think it is more natural and much more obvious to just store variables in outer states. Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

"Andreas Huber" <ahd6974-spamgroupstrap@yahoo.com> writes:
Can't we call that thing "the state's associated data object?" Calling it "the state" gives me the willies. It goes against the grain of the English meaning of state (singular, not substance) and also the one used in the FSM abstraction.
Sorry, details please? Where is this example?
Fair enough. It could also be done by non-intrusive specialization: template <> struct associated_data< player , vector_c<player::state, some-list-of-states>
{ typedef some-data-type type; }; But I admit that's getting unweildy.
Do you agree with Mr. Nasonov that outer states should be implemented as base classes of inner states? 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. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams <dave <at> boost-consulting.com> writes:
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...
http://tinyurl.com/5q9hk (State-local storage)
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.
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.

Andreas Huber <ahd6974-spamgroupstrap@yahoo.com> writes:
No, I mean the thing you're calling "the state." It's really the collection of data that is live when the machine is in a particular state. The machine's state does _not_ correspond to the identity of that object. Maybe it corresponds to that object's type.
Let me know if you're still confused.
So, it's a shorthand for writing the same transition to stop out of all of its substates.
Copying data doesn't extend its lifetime; it makes a copy. It may be important not to destroy the original. Furthermore, the original may not be copyable. <snip>
I see. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote: [snip]
That's pretty much agreed-upon terminology. The word "state" in the FSM field refers to two different things: 1. From <http://en.wikipedia.org/wiki/State_%28computer_science%29>: <quote>In information processing, a state is the complete set of properties (for example, its energy level, etc. see state (physics)) transmitted by an object to an observer via one or more channels. Any change in the nature or quantity of such properties in a state is detected by an observer and thus a transmission of information occurs.</quote> By this definition one would say that an FSM *has* a particular state. I assume that's the definition you use. 2. In state charts people call the boxes or circles (see e.g. <http://en.wikipedia.org/wiki/State_diagram#Mealy_machine>) also states. By this definition one would say that an FSM *is* *in* a particular state.
Exactly.
The machine's state does _not_ correspond to the identity of that object.
Right.
Maybe it corresponds to that object's type.
... plus the auxilary data objects that are used/accessible when the machine is in that state.
I hope not.
Yes, or more verbosely, the self-transition on Active expresses that no matter in what inner state (Running or Stopped) the machine currently is, EvReset will always trigger an exit out of the currently active inner state and the Active state. After that the Active state is entered and then the Stopped state is entered (because it is the initial state inside Active).
Agreed. Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.
participants (4)
-
Alexander Nasonov
-
Andreas Huber
-
David Abrahams
-
Jonathan Turkanis