
Hi Richard,
the attached example I think shows 2 problems.
1st is that the deferral of event3 is not happening. 2nd is that the no_transition function is never called.
the output of the run is :
MS1 Entering State: Idle by: event1 MS1 Leaving State: Idle by: event1 MS1 Entering State: SubRunning by: event1 FwdGuard: returns:1, event: event2 Processing BaseEvent Instance(event2) Setting guard false FwdGuard: returns:0, event: event3 FwdGuard: returns:0, event: event4 FwdGuard: returns:0, event: event5 MS1 Leaving State: SubRunning by: event5 MS1 Entering State: AfterSub by: event5
I think it shall be :
MS1 Entering State: Idle by: event1 MS1 Leaving State: Idle by: event1 MS1 Entering State: SubRunning by: event1 FwdGuard: returns:1, event: event2 Processing BaseEvent Instance(event2) Setting guard false FwdGuard: returns:0, event: event3 FwdGuard: returns:0, event: event4 MS1 no_transition event (event4) MS1 Leaving State: SubRunning by: event5 MS1 Entering State: AfterSub by: event5 MS1 no_transition event (event3)
So in this example event3 and event4 are never triggered a transition ... the Row < SubRunning , baseEvent , none , ProcessBaseEvent , FwdGuard
was guarded by the FwdGuard for these events.
Is my expected behavior wrong ?
Well, hard to answer because the Standard does not discuss conflicts between a state declaration and a transition, so your guess is as good as mine ;-) Let's say that this is the intended behavior. In the current implementation, the state declaration has the lowest priority. This means the transition table comes first, and if it handles the event, then processing stops here so your deferred declaration has no effect. The answer to the question in your title is yes. If a guard rejects the event, the event is really handled (rejection is a perfectly acceptable event handling) so there is no call to no_transition, which is to be seen as a catch-all error handler in case you forget to handle an event. Seeing that the default version is an assert, imagine what you'd get at every guard rejection ;-)
If guard is executed but the transition actually is triggered because it is guarded out why this event treated as handled event ?.
Because a guard is not an error, a call to no_transition probably is. I think the best way to solve the conflict between state declaration and the transition table wanting to process is to state what you want in the transition table itself: Row < SubRunning , event3 , none , Defer , none /* or guard */ > will do. Well, there is a small bug, but not where you expect it. It seems that the processing continues even though this transition defers the event. I just fixed this in the trunk (rev. 75641).
This 2 problems breaks my current nested state machine implementation because I'm using no_transition to forward the event to the outer state machine. I'm confused :(.
I think this will not work (and should not) because there is no call to no_transition in a submachine (I don't see it here but I suppose your real code is bigger). The reason is the same as above, no_transition is an error and will assert. But if a submachine cannot process an event, it is not necessarily an error, the outer machine should get its chance to process the event. I'm also afraid you're trying to keep a pointer to the outer machine to process the event (cycle). I suggest pushing the event to a pseudo exit, which will achieve the same a better way. HTH, Christophe