
First, I appologize for messing up the threading, but I get the digest and so can't respond directly.
Have you ever had a look at other FSM libraries? I think boost::fsm is less messy than any other library I've seen.
Unfortunately, no. My response is based on the fact that 1) I generally think I know what fsm are about, 2) I'm comfortable seeing complex template stuff, yet 3) sample code for simple state machines just didn't click for me. I feel like I'm in the target audience of the library, so I'm looking deeper to see if I can figure out why.
// I guess there's no way to avoid declaring // these ahead of time?? class Machine, State1, State2, Event1, Event2;
Actually there is, but I found out about this only recently (Peter Dimov mentioned this in an unrelated post) and haven't changed the docs because I feared that this does not work on all compilers:
Instead of
struct Greeting; struct Machine : fsm::state_machine< Machine, Greeting > {};
you can write:
struct Machine : fsm::state_machine< Machine, struct Greeting > {};
Ok, good to know. I'd like to hash out what the "ideal world" would look like and compromise from there, if you know what I mean.
struct S1Data { int i; S1Data() : i(0) {} };
typedef simple_state< Machine, S1Data, BOOST_TYPEOF( cout << constant("Entering State1.") ), BOOST_TYPEOF( cout << constant("Exiting State1.") ), on_event<Event1, BOOST_TYPEOF( _1->i++ ) >, transition<Event1, State2> > State1; // the "data" member of State1 has type S1Data, and is // passed into event handlers
You consider this more readable? Sorry, I have to disagree. For entry and exit actions and extended state variables I consider my approach superior, for reaction definition, your approach seems about equivalent.
I think this is how my example would look using the current library, right? struct State1 : simple_state< State1, Machine, custom_reaction< Event1 >, transition< Event1, struct State2 > > { int i; State1() : i(0) { cout << "Entering State1."; } ~State1() { cout << "Exiting State1."; } result react( const Event1 & ) { i++; } }; That's actually not so bad. I've defined both a reaction and a transition on the same event; not sure if you're supposed to do that. Now I'm wondering if there's a way with mpl to determine if a class has a function with a certain signature. Can you eliminate the need for "custom_reaction< Event1 >" and just test whether or not the class implements "result react( const Event1 & )" ? If you could somehow hide the CRT mechanism, and specify children instead of parents, maybe you could boil down to something like so: DEFINE_STATE(State1, transition< Event1, struct State2 >) { int i; State1() : i(0) { cout << "Entering State1."; } ~State1() { cout << "Exiting State1."; } result react( const Event1 & ) { i++; } }; And I think that's about as obvious as you can make it. But that may just be wishful thinking.
I don't understand, you do define states top-down in boost::fsm.
Maybe I'm confused, but as best as I can tell, you specify parents instead of specifying children. So, if StateX has StateY and StateZ as inner states, instead of saying StateX : StateY + StateZ, you say StateY -> StateX; StateZ -> StateX.
it's my impression that with mpl one can iterate through the template arguments and figure out if they are events or transitions or whatever. So I smushed together the different
One sure can but that would duplicate mpl::list<> functionality to a certain degree.
For "real-world" uses, this seems unimportant. However, for the tutorial and basic examples, I think it would be a good idea if you can silently ignore mpl. Of course those examples should compile and work... I don't have a feel for whether I'm asking for a mountain or a molehill here, so I'll let it be.
Given that the approach you outlined above really works, I think you can use lambda for transitions without changing a single line of boost::fsm, you simply define your own reaction that accepts typeofed lambda expressions instead of function pointers for transition actions. I'm not so sure whether the same is possible with entry/exit actions but I'm inclined to think that it is (that would require deriving your own state class template from simple_state).
Most people get used to the syntax of boost::fsm quite quickly. Also, I've received feedback that
I think it would be nice to have a mechanism that accepts lambdas, though I'll concede it is better to avoid it for "average joe" programmer. But since fsm is compile time, an advanced user might use another library/technique to programmatically generate the code she wants as a lambda type. It's always seemed that lambda had great potential as a compile time code generator, and fsm is a place where one might concievably stick it. people
really like the fact that they can easily put the bodies of complex actions in cpp files, I *guess* that would be a little more difficult with your approach.
Now I'm thinking that maybe a macro or two added to what you've got, just to hide some of the machinery, is all that it would take to get what I'm looking for. I'll grant you that I'm struggling to come up with what I think is "ideal." My main goal is boost::fsm using code should be reasonably "guessable" by an educated reader in short order. Basically, my coworkers should be able to look at my code and mostly be able to guess what was going on. [snip]
I'd say it takes one day tops of playing around with boost::fsm to learn this.
My concern is intimidating potential new users more than necessary. Like I said initially, I might have missed a ton of discussion about this from before. If you can point me to a thread where interface issues were hashed out in great detail already, I'll take a look.
I did consider using named template parameters, but rejected it because it would add to the amount of text you have to write and would offer a benefit only for beginners.
Me, I would probably cater a little more to the beginners, since I think getting more people to use FSM than previously would have to be a good thing.
tutorial just made my head spin, especially trying to figure out how states and machines get tied together (this is still unclear to me).
I guess you mean how the implementation ties them toghether? As a user, why do you need to know that?
As I already mentioned in another post: Targetting every C++ developer would require an *additional* document at least as thick as the current tutorial. I think it is reasonable to expect
When I first looked at the sample code, I was hunting high and low, thinking to myself, "Where on earth does it specify which states belong to which?" previous
exposure to FSMs.
Yes, I do not suggest writing your own guide to FSMs.
In general, I would drop all mention of UML except for some appendix somewhere (and the reference manual too).
Why?
I think it's a distraction. Sure, it's great that you've got this nice correspondance with UML, but that's unimportant *in the tutorial*. Mention it on the about page, have an appendix all about it, go into detail in the references, etc.
"Getting Started" and "Target Audience" should be in a differenct document, and
Please make a suggestion.
Probably just in index.html.
"How to read this tutorial" should be removed.
Why?
To me, is unnecessary verbiage. It doesn't say anything important. Perhaps you need better headings in the TOC. The ToC is currently broken up by the name of the example; perhaps rather than "StopWatch," say "Simple Finite State Machines - A StopWatch example."
In general, all of your "remarks" and "comments" need to be in the code!
You're the second person to request that. I personally think it is better to not clutter code with too many comments. If people think it is better to have all comments in the code, I'll sure change it.
I think the example state machines are basically OK, but I think that it is absolutely essential that you include a simple example that is alphabet-based. In fact, some helper functions for alphabet-based languages are probably a good idea, just to make
Having it in the code, both in the tutorial and in the example files, would help a lot, IMO. Especially the example files. If you could give me a better overview of the process and hold my hand better about which template parameters are which, I think I would have been much less confused. the
tutorial easier.
Why?
Well, maybe this isn't the norm, but I was taught FSMs using alphabets-as-events. One of the first things *I* would do with the library is try and implement some examples out of my old college text. I figured most people were taught this way, and so having an example with that would help connect with something familiar.
You mean the mapping between the pressed key and the generated event? Why?
I think it's probably a common thing to want to test your state machine by triggering events from the keyboard in a console app.
I'm confused about why entering/exiting states causes construction/ destruction. It's taken as a given,
It is not: http://tinyurl.com/5mjra (State-local storage)
That's explaining why you offer state-local storage, which I have no qualms with. It doesn't explain why you use the constructor/destructor mechanism, it's just stated that's the way it is.
but I would tend to assume that state-local-storage is maintained throughout unless I explicitly reset it.
Why?
Ok, I think I figured something out since I wrote this. You're relying on nesting states to maint data. I think this needs to be explained in big neon signs. I don't think of exiting a state as destroying it, just that it's no longer "active" or whatever. Your model is like a window manager that closes a window every time a different window gets the focus and reopens the first window upon return. Of course, having lost all data imbetween. Maybe hoisting your data up to an enclosing space is a good idea, but I'm not used to working with nested states, so I don't really think that way. I'm willing to be convinced, although I'm suspicious.
I'm also surprised by the lack of "accept" states. Maybe it's not universal, but my theory certainly had them, and it's just disconcerting for them not to be there.
I don't know what accept states are. UML doesn't have them.
Now, I'm in no way an academic, so I'm relying on Wikipedia to tell me what's "normal." Since it's in line with my old textbook, I guess it's reasonably standard. Wikipedia tells me that there "acceptor" and "transducer" finite state machines. I've not worked with the "transducer" variety before; my text deals with them only in the exercises. At any rate, with an "acceptor" FSM, if after processing all input you are in an "accept" state, the input was legal, the operation was successful, whatever. Otherwise there was an error. Not that everybody will use them, but it would be nice to be able to mark states as accept-states and ask the machine if the current state is an accept-state. I would certainly recommend adding http://en.wikipedia.org/wiki/Finite_state_machine to your list of links about FSMs. Cheers- Augustus __________________________________ Celebrate Yahoo!'s 10th Birthday! Yahoo! Netrospective: 100 Moments of the Web http://birthday.yahoo.com/netrospective/