State Transitions in Frame Machine Notation

The wisdom of Buckaroo Banzai

Unless you are in Oakland — or writing spaghetti code. See

for graphic details about indeterminism with traditional coding techniques.

State machines, however, are marvelous at making it obvious exactly where you are and how you can get somewhere else.

How to get to Oz and back

This article will continue exploring the Frame Machine Notation (FMN), which is a Domain Specific Langauge (DSL) for defining automata (state machines) and builds upon ideas introduced by UML statecharts.

Statecharts is a visual design specification for modeling software invented by Dr. David Harel that introduces a number of enhanced concepts over traditional state machine definitions.

Statecharts introduced groundbreaking ideas for automata including the special enter and exit events that occur when a machine transitions between states. These events provide “hooks” for initializing and cleaning up states and serve as constructors and destructors for states.

In the previous article, we took a look at the state change notation:

->> $NewState // state change

This expression generates the following code:

_state = NewState // state change

This is simple to understand and a fast to execute but does not send enter or exit events (by definition). When they aren’t used by the machine it is best to not incur the overhead of sending them.

To differentiate a state change from a transition, we need to introduce a new “transition” notation and define a mechanism for implementing it.

->> $NewState    // state change - doesn't send any events
-> $NewState // transition - sends exit then enter events

So how are transitions implemented? This is the “mechanism” you need to add to your controller:

func _transition(newState:FrameState) {        
_state(new FrameEvent("exit")) // send current state an |exit|
_state = newState // change state
_state(new FrameEvent("enter")) // send new state an |enter|
}

The _transition(newState:FrameState) function simply takes a reference to the next state function to reference. Before changing the state, the current state is sent the |exit| event and after the state change, the new state is sent an|enter| event.

A simple example will demonstrate the sequence of actions. Assuming the machine below started in $S1 and then received a |toggle| event:

$S1
|toggle| -> $S2 ^
|exit| print("exit $S1") ^
$S2
|enter| print ("enter $S2") ^

the following output would be generated:

exit $S1
enter $S2

We can now explore how Dorthy traverses her own little multiverse using Frame:

The code above initializes in the $Begin state and then transitions into $S1 when sent a |start| event. An important detail to note is that $Begin is never transitioned into as the machine is initialized directly to be in $Begin. The side effect is that the $Begin state will never receive an |enter| event! However, upon transitioning to $S1, it will receive an |exit| event.

After transitioning to $S1, the machine will simply toggle back and forth between $S1 and $S2. The output will be a never-ending stream of:

Starting
Dim the lights!
That dog's a menace to the community
Aunty Em!
We aren't in Kansas anymore
There's no place like home!
That dog's a menace to the community
Aunty Em!
We aren't in Kansas anymore
There's no place like home!
....

While these action “hooks” are powerful, they do come at a significant cost. Each transition results in three function calls as well as the allocation of two FrameEvent objects. Therefore when the enter/exit are not used, it is much more efficient to do a simple state change instead.

One excellent use of |enter| and |exit| events are to make sure that resources scoped to a state are properly created and destroyed. Managing a timer resource is a typical use case:

$TimedAnswer
|enter| startTimer(10000) ^ // create, start and cache timer
|timeout| -> $TimedOutState ^
|answered| -> $CheckAnswer ^
|exit| stopTimer() ^ // stop, destroy and deref timer

The startTimer() function is assumed to allocate, start and keep a reference to a timer. The stopTimer() should do the inverse operations. What is nice is that regardless of if the |timeout| event happens or the |answered| event happens the |exit| event handler will take care of cleaning up the timer.

Summary

This has been a very quick introduction to transitions, a key feature in Frame. As we have seen, the transition mechanism is easy to understand as well as implement in any object-oriented language. When |enter| and |exit| events are not needed to trigger behavior during a change of state, it is much more efficient to use the state change notation introduced in the last article.

Related Articles

A professional software developer and manager. I believe Agile planning is a real thing.