[statechart] process_event vs post_event confusion
I'm seeing a usability issue between post_event and process_event. Basically, depending on where in the state itself I'm executing an event, I need to know which to invoke. My understanding is that if I'm calling within the context of the constructor of the state, I need to use post_event. Anywhere else (outside of construction, but still within a member function of the state subclass itself), you invoke "context<MyMachine>().process_event()". Why can't post_event() automatically query the state machine to see if it is "busy" constructing a state, and if it isn't, forward the event to process_event() for me instead? Is there really a reason to have to make a logical decision between the two in code? I'm using boost::statechart in my code at $DAYJOB and this is a reasonable complaint I get in my code reviews, especially from those not very familiar with boost itself. They have an expectation for the implementation of the state machine to be intuitive and easy to understand.
I can't speak for the author, but I have used statechart extensively over the years. Process_event and post_event operate fundamentally differently, and I don't think it is a good idea to mask the differences by forcing them into the same API. Think if process_event as synchronous event handling. (Do not confuse with asynchronous state machines.) The function call doesn't return until after event processing completes. If the state machine is not already in a stable state, there is no right answer to what this should do. On the other hand, post_event queues up the event for processing once any existing event processing completes. Hence, if called from the state machine while in an unstable state, the state machine will wait to be stable before invoking the event. But the actual function call returns immediately. The caller has to be aware of the differences. Upon return from calling post_event, event processing has not yet occurred. Upon return from process_event, it has. Theoretically you could get away with always calling post_event, but not the other way around. You have to be aware of which one you are calling. Dan Kelly djkelly@computer.org (484) 769-2961
On Mar 29, 2017, at 11:06, Robert Dailey via Boost-users
wrote: I'm seeing a usability issue between post_event and process_event. Basically, depending on where in the state itself I'm executing an event, I need to know which to invoke. My understanding is that if I'm calling within the context of the constructor of the state, I need to use post_event. Anywhere else (outside of construction, but still within a member function of the state subclass itself), you invoke "context<MyMachine>().process_event()".
Why can't post_event() automatically query the state machine to see if it is "busy" constructing a state, and if it isn't, forward the event to process_event() for me instead? Is there really a reason to have to make a logical decision between the two in code?
I'm using boost::statechart in my code at $DAYJOB and this is a reasonable complaint I get in my code reviews, especially from those not very familiar with boost itself. They have an expectation for the implementation of the state machine to be intuitive and easy to understand. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
So the specific issue is different from what you have listed.
I have several states that perform a basic task: They register to a
publish/subscribe mechanism in their constructor and send a "command"
that will eventually get a response. This is not threaded, but in a
game-loop type fashion, there is a loop on the main thread that
invokes an update function on the publish/subscribe mechanism, which
eventually results in the registered callback on the state being
invoked later on well after that state was constructed.
When that callback is invoked, the state processes the "response" to
that command sent earlier and transitions to the next state via
post_event() (because originally that's what I thought I had to do
inside the state itself, regardless of whether it was happening in the
constructor or not). In actuality, because post_event() was being
called while the state machine was *not* blocked (because it was
outside the constructor), the event queue was never actually
processed. There is no real way to tell the state to invoke the state
machine to process the event queue at this specific point. So what
happens is I exit the callback and the state transition never happens.
There is no way to invoke processing of the event queue from the state
machine outside of initialize() and process_event(), neither of which
I need to call after the state transitions itself.
The solution for now was to call process_event() from within the
state's callback member function. This resulted in an immediate
transition to the next state prior to exiting the previous state's
callback method.
This is where my feedback comes into play. It's not very intuitive to
see that post_event() is called in state constructors but
process_event() is called in member functions of that same state which
are invoked outside of construction. This is not self documenting.
Like I said, several developers on my team not too familiar with boost
statechart gave reasonable feedback in this regard.
I think from the perspective of self-transitioning states, the
difference between post_event and process_event is moot. The end
result is the same: We transition to the next state. That's the
desired effect. To achieve this effect, the choice between one or the
other could be automated and improve the intuitiveness of the code.
Just my opinion on the matter. Would like to hear back from the author
though on his thoughts, maybe there's already an existing alternative
available that addresses my concerns.
On Thu, Mar 30, 2017 at 8:36 AM, Dan Kelly
I can't speak for the author, but I have used statechart extensively over the years. Process_event and post_event operate fundamentally differently, and I don't think it is a good idea to mask the differences by forcing them into the same API.
Think if process_event as synchronous event handling. (Do not confuse with asynchronous state machines.) The function call doesn't return until after event processing completes. If the state machine is not already in a stable state, there is no right answer to what this should do.
On the other hand, post_event queues up the event for processing once any existing event processing completes. Hence, if called from the state machine while in an unstable state, the state machine will wait to be stable before invoking the event. But the actual function call returns immediately.
The caller has to be aware of the differences. Upon return from calling post_event, event processing has not yet occurred. Upon return from process_event, it has. Theoretically you could get away with always calling post_event, but not the other way around. You have to be aware of which one you are calling.
Dan Kelly djkelly@computer.org (484) 769-2961
On Mar 29, 2017, at 11:06, Robert Dailey via Boost-users
wrote: I'm seeing a usability issue between post_event and process_event. Basically, depending on where in the state itself I'm executing an event, I need to know which to invoke. My understanding is that if I'm calling within the context of the constructor of the state, I need to use post_event. Anywhere else (outside of construction, but still within a member function of the state subclass itself), you invoke "context<MyMachine>().process_event()".
Why can't post_event() automatically query the state machine to see if it is "busy" constructing a state, and if it isn't, forward the event to process_event() for me instead? Is there really a reason to have to make a logical decision between the two in code?
I'm using boost::statechart in my code at $DAYJOB and this is a reasonable complaint I get in my code reviews, especially from those not very familiar with boost itself. They have an expectation for the implementation of the state machine to be intuitive and easy to understand. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (2)
-
Dan Kelly
-
Robert Dailey