Defining sub state machines

A common concept for structuring statecharts is the decomposition into different sub state machines. This is a concept that you can find in modeling languages like the UML and others.

The basic idea is that a state machine which is assigned to a state as sub machine is executed as if it is part of the enclosing state machine. This means its life cycle is coupled to the life cycle of its owning state. It will be activated when its parent state becomes active, and will be deactivated when the parent state deactivates.

Such a sub machine pattern can be defined using the life cycle methods introduced in the previous chapter. The pattern for using sub state machines looks like this:

entry / otherMachine.enter
oncycle / otherMachine.runCycle 
exit / otherMachine.exit

The call to runCycle is only required if the referenced state machine is cycle-based. The equivalent is the following statement:

submachine otherMachine

The submachine statement is not only a shortcut. It is more expressive, less verbose and avoids errors by applying higher level validations. You can simply use this statement like any other within the state. Using it is recommended when you want to use sub state machines.

So lets take a look how sub state machines can be applied to the traffic control example. The state Operate contains several sub states which control the traffic flow by alternately releasing and blocking the traffic flow of the two directions.

Traffic controller raises events on referenced state machines.

This set of sub states consists of two groups which are similar to each other. The first group consists of the states all blocked before A, Release A, and A Released. The second group is identical except for the fact that A is replaced by B. So the behavior is cloned. Sub state machines can be used to eliminate such redundancies.

Using sub machine in traffic control.

Here, introducing the submachine required three steps.

  1. Create a new statechart ReleaseProcess.sct and copy the three states of the identified group. As the statechart should not be specific for a specific traffic light it requires a variable to reference the controlled state machine: var trafficLight : TrafficLight
  2. Replace each group by a single state. These are Process A and Process B here.
  3. Integrate the new statechart ReleaseProcess as a sub state machine.
    • This requires an additional variable which holds the reference to the sub state machine: var process : ReleaseProcess
    • The new states integrate the submachine. On entry, the new process state machine is configured with the proper traffic light state machine: entry / process.trafficLight=trafficLightA
    • The sub machine is hooked into the state: submachine process
    • The transitions of the two states are triggered when the ReleaseProcess state machine has finished its work and is in a final state. The guard is defined on the transitions: [process.isFinal]

This results in the following TwoWayTrafficController and ReleaseProcess state machines:

Traffic controller raises events on referenced state machines.

This example shows a typical scenario where using sub machines makes much sense. Here, sub machine controls a process which consists of several steps. Here, it just contains a happy case but it may also define error states. This process can be reused easily if the state machine should be extended to a 3 or 4-way traffic control. So setting up a 4-way traffic control in the initial statechart would require 4x3=12 states while using a sub machine requires 4+3=7 states.

In this example the state machine process is used as sub machine in both states Process A and Proces B. When state machine process reaches its final state, the state transition from state Process A to state Process B will be executed. During this state transition, first, Process A will be exited. As a result also the sub machine will be exited. Second, Process B will be entered. As a result, the process state machine will be configured to use the other traffic light state machine and the process state machine will be activated by calling its enter operation. This will activate the initial state Safe. So the process state machine is reset to control the next process.

Sub machines are comparable with sub regions and as it is possible to define multiple sub regions for a state it is also possible to define any number of sub state machines. It is even possible that a state defines both – sub regions and sub machines. If both are defined then they are processed according to the execution order:

  • In the case of @ChildFirstExecution the sub regions are processed first.
  • In the case of @ParentFirstExecution the sub machines are processed first.

Additionally, the order of the submachine statement within a state’s behavior definition is relevant for the execution order:

  1. Submachines are entered, exited, and executed (runCycle call) according to the order of the submachine statements.
  2. Entry actions which are defined before the submachine statement are executed before entering the sub machine. Those defined after are executed later. This may be relevant for properly setting up sub machines.
  3. Exit actions which are defined before the submachine statement are executed before exiting the sub machine. Those defined after are executed later. This may be relevant for properly tearing down sub machines.
  4. In the case of cycle-based sub machines all local reactions of a state which are defined before the submachine statement are executed before executing the sub machine’s run-to-completion step. Those defined after are executed later.

As shown in the example a state machine can be used as a sub machine within different states. The only constraint that must be considered is that these states must be exclusive to each other so that both states can’t be active at the same time. In other words, a machine can only be a sub machine in one active state at once. The subsequent use of a state machine as sub machine is no problem.