|
Boost : |
From: Augustus Saunders (infinite_8_monkey_at_[hidden])
Date: 2005-03-02 19:47:21
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).
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.
>Most people get used to the syntax
>of boost::fsm quite quickly. Also, I've received feedback that
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?
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?"
>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
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.
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.
>> 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
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/
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk