Data Management with Frame State Variables

Mark Truluck
6 min readMay 25, 2024

--

(Frame is a new Domain Specific Language (DSL) focused on enabling developers to easily create programs using automata. See the Frame documentation as well as Getting Started With Frame to find tools and other resources to explore the Frame language.)

One of the key innovations in Frame that differentiates its syntax and implementation from other software modeling, low-code and workflow language approaches is the ability to create local variables in states.

$Start

// State variables are declared before any
// event handlers.

var counter = 0

Above we see a state that declares a counter variable and initializes it to 0.

NOTE: State variables must be declared before any event handers in the state.

fn main {

// Instantiate a Frame controller.

#StateVariableDemo1()
}

#StateVariableDemo1

-machine-

$Start

// State variables are declared before any
// event handlers.

var counter = 0

// The enter event handler will print the value
// of the counter when transitioning into the state.

|>|
print("Enter $Start")
print("counter = " + str(counter)) ^

##

Upon execution, the program prints out the following:

Enter $Start
counter = 0

It might have been expected that the system would not print anything at all as there was no actual transition into the state from another state. However, the Frame runtime sends an enter event to the machine upon startup. This can be thought of as a “default transition” from the not running state to the running start state.

State Variable Scope

State variables remain valid as long as the system maintains a reference to the state. This condition is met, of course, as long as the state is the “current” state for the system. However, there are important situations where a state instance and its related data is maintained even when not the current state. We will explore these situations later in the article.

The reason this is possible is that states in Frame are actually instances of a state data structure. Upon entry to a state, Frame creates a new instance of this data structure and initializes it and its associated variables. This data structure is called a Frame state compartment, or sometimes just compartment. Upon exit, if not preserved by the runtime, the state compartment will be destroyed.

Below we can see an enhancement to the demo showing that the counter variable is persisted while in the state and in scope between calls to the event handler:

fn main {

// Create a new Frame controller

var demo:# = #StateVariableDemo2()

// counter == 0

// Increment the state variable 3 times

demo.inc()
demo.inc()
demo.inc()
}

#StateVariableDemo2

-interface-

inc

-machine-

$Start
// State variables are declared before any
// event handlers.

var counter = 0

// The enter event handler will print the value
// of the counter when transitioning into the state.
|>|
print("Enter $Start")
print("counter = " + str(counter)) ^

// The counter variable is local to the state instance
// and keeps increasing while we stay in the state.
|inc|
counter = counter + 1
print("counter = " + str(counter)) ^
##

Below is the output from running the program. Each call to the inc interface method increments counter and prints the current value.

Enter $Start
counter = 0
counter = 1
counter = 2
counter = 3

State Reentry Creates New State Instance

To demonstrate Frame compartments in action, we will modify the program to support a self transition back into $Start when the transition interface method is called.

Self transition to $Start resets counter variable
fn main {

// Create a new Frame controller

var demo:# = #StateVariableDemo3()

// counter == 0

// Increment the state variable 3 times

demo.inc()
demo.inc()
demo.inc()

// counter == 3

// Transition back into $Start.

demo.transition()

// counter == 0

demo.inc()

// counter == 1
}

#StateVariableDemo3

-interface-

inc
transition

-machine-

$Start
// State variables are declared before any
// event handlers.

var counter = 0

// The enter event handler will print the value
// of the counter when transitioning into the state.

|>|
print("Enter $Start")
print("counter = " + str(counter)) ^

// The counter variable is local to the state compartment
// and keeps increasing while we stay in the state.

|inc|
counter = counter + 1
print("counter = " + str(counter)) ^

// Transitioning out of the state destroys
// the state compartment and creates a new one.
// This will create a new data structure and
// initialize the new counter variable to 0.

|transition|
print("Transitioning back into $Start" )
-> $Start ^
##

Here is the program output:

Enter $Start
counter = 0
counter = 1
counter = 2
counter = 3
Transitioning back into $Start
Enter $Start
counter = 0
counter = 1

As we can see above, the transition back into the $Start state doesn’t maintain the counter value. This demonstrates that a completely new state compartment data structure has been initialized and is now the current state.

Frame History with State Compartments

Frame semantics support Statechart concepts which include a history mechansim for returning to a previous state.

In our last demo, we will use the Frame state stack operators to save the current state before a transition and then again to return to the previous state compartment. In doing so, we will demonstrate that we are, in fact, returning the exact previous compartment and not a new one like in the last demo.

fn main {

// Create a new Frame controller

var demo:# = #StateVariableDemo4()

// counter == 0

// Increment the state variable 3 times

demo.inc()
demo.inc()
demo.inc()

// counter == 3

// Transition to $Pause

demo.transition()

// Transition back to saved state instance - $Start

demo.transition()

// counter == 3
}

#StateVariableDemo4

-interface-

inc
transition

-machine-

$Start
// State variables are declared before any
// event handlers.

var counter = 0

// The enter event handler will print the value
// of the counter when transitioning into the state.

|>|
print("Enter $Start")
print("counter = " + str(counter)) ^

// The counter variable is local to the state compartment
// and keeps increasing while we stay in the state.

|inc|
counter = counter + 1
print("counter = " + str(counter)) ^

// Transitioning out of the state destroys
// the state compartment and creates a new one.
// This will create a new data structure and
// initialize the new counter variable to 0.

|transition|

// Push current state compartment on the
// state stack and transition to $Pause

$$[+] -> $Pause ^

$Pause

|>|
print("Enter $Pause") ^

|transition|

print("Return to $Start")

// Now return to the previous $Start state compartment.
// The counter will still be 3 rather than 0.

-> $$[-] ^
##

Below we can see the two transition calls drive the system to first transition to $Pause and then transition back into the last state saved on the History state stack:

Here is the output from the program:

Enter $Start
counter = 0
counter = 1
counter = 2
counter = 3
Enter $Pause
Return to $Start
Enter $Start
counter = 3

As we can see, the transition to the saved state compartment using the history mechanism restored the first instance of $State with the counter value of 3. This demonstrates the persistence and restoration of the $Start state compartment.

Conclusion

In this article we have seen how Frame’s implementation of state compartments allows for easily storing data local to a state instance. As long as the the system remains in a state, changes to the local state values are persisted. This is extended to Frame’s history mechanism which allows for saving and returning to the exact state instance that the system was previously in.

Use of state compartments by Frame is mostly invisible to the programmer, easy to use and would be challenging to implement in a hand crafted state machine. This approach to state management distinguishes Frame from all other low-code and automata programming approaches (to the best of the author’s knowledge).

--

--

Mark Truluck
Mark Truluck

Written by Mark Truluck

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

No responses yet