Frame event handlers are terminated with two operators:
Operator | Meaning |
---|---|
^ | return |
:> | continue |
Return is, by far, the most common of the two. Lining up the Frame notation with the C# code it generates we can see how they align:
Frame Notation | C# code |
---|---|
$EventTerminators |return| ^ |continue| :> | private void _sEventTerminators_(FrameEvent e) { if (e._message.Equals("return")) { return; } else if (e._message.Equals("continue")) { } } |
Note that the continue is, from a code generation standpoint, a no-op in that it doesn’t generate anything. This enables the execution to simply fall through to whatever code is below the tests for event handler messages.
This approach enables a simple way for a child state event handler to do something and then pass the event on for further processing by the parent state:
Frame Notation | C# code |
---|---|
#ReturnVsContinue -interface- _return @(|return|) _continue @(|continue|) -machine- $Child => $Parent |return| log("saw return in $Child") ^ |continue| log("saw continue in $Child") :> $Parent |return| log("saw return in $Parent") ^ |continue| log("saw continue in $Parent") :> -actions- log [msg:string] ## | public partial class ReturnVsContinue { public ReturnVsContinue() { _state_ = _sChild_; } //===================== Interface Block ===================// public void _return() { FrameEvent e = new FrameEvent("return",null); _state_(e); } public void _continue() { FrameEvent e = new FrameEvent("continue",null); _state_(e); } //===================== Machine Block ===================// private void _sChild_(FrameEvent e) { if (e._message.Equals("return")) { log_do("saw return in $Child"); return; } else if (e._message.Equals("continue")) { log_do("saw continue in $Child"); } _sParent_(e); } private void _sParent_(FrameEvent e) { if (e._message.Equals("return")) { log_do("saw return in $Parent"); return; } else if (e._message.Equals("continue")) { log_do("saw continue in $Parent"); } } //===================== Actions Block ===================// protected virtual void log_do(string msg) { throw new NotImplementedException(); } //=============== Machinery and Mechanisms ==============// private delegate void FrameState(FrameEvent e); private FrameState _state_; } |
As both return
and continue
are reserved words in many target languages, we expose the interface methods using a _
prefix and use the alias notation to send the |return|
and |continue|
messages. This is a good example of how the alias feature comes in handy to accommodate target language interface requirements while maintaining standard or desirable messages internally to drive the state machine.
Here is the working demo for the spec: