Chapter 7: Implementation Strategies for State Machines

Once you’ve modeled your statechart, the next step is bringing it to life: implementing it as real, executable software.
There are several strategies to do this — each with their own strengths, weaknesses, and typical use cases.

Choosing the right strategy depends on:

Let’s explore the major approaches based on the following example statechart.


Code-Only Approaches

Code-only implementations don’t rely on any external libraries. They are fast, lightweight, and highly optimized — but also harder to maintain by hand.

Switch/Case Implementation

The most common and classic approach looks like this in C code:

enum State { Off, On } state = Off;
int onCount = 0;
bool isOn = false;

void handleEvent(Event event) {
    switch (state) {
        case Off:
            if (event == buttonPressed) {
                isOn = true;            // transition action
                onCount += 1;           // entry action
                state = On;
            }
            break;
        case On:
            if (event == buttonPressed) {
                isOn = false;           // transition action
                state = Off;
            }
            break;
    }
}

✅ Advantages:

❌ Disadvantages:


State Transition Table

In this approach, the entire state machine is declared declaratively in a table.

typedef struct {
    State current;
    Event trigger;
    State next;
    void (*action)();
} Transition;

void toOn()  { isOn = true; onCount += 1; }
void toOff() { isOn = false; }

Transition table[] = {
    { Off, buttonPressed, On,  toOn },
    { On,  buttonPressed, Off, toOff },
};

void handleEvent(Event event) {
    for (int i = 0; i < NUM_TRANSITIONS; ++i) {
        if (table[i].current == state && table[i].trigger == event) {
            table[i].action();
            state = table[i].next;
            break;
        }
    }
}

The logic is completely separated from the state machine structure. Transitions are just data. Actions are function pointers that can be reused or extended.

✅ Advantages:

❌ Disadvantages:


State Pattern (Object-Oriented)

This uses classic object-oriented design:

class State {
public:
    virtual void onButtonPressed(Context& ctx) = 0;
};

class OffState : public State {
public:
    void onButtonPressed(Context& ctx) override {
        ctx.isOn = true;
        ctx.onCount++;
        ctx.setState(new OnState());
    }
};

class OnState : public State {
public:
    void onButtonPressed(Context& ctx) override {
        ctx.isOn = false;
        ctx.setState(new OffState());
    }
};

class Context {
public:
    int onCount = 0;
    bool isOn = false;
    State* state = new OffState();

    void setState(State* s) { delete state; state = s; }
    void buttonPressed() { state->onButtonPressed(*this); }
};

✅ Advantages:

❌ Disadvantages:


Library-Based Approaches

Popular frameworks like Spring StateMachine, Boost MSM, and Qt State Machine Framework provide:

✅ Advantages:

❌ Disadvantages:


Interpreter-Based Approaches

Interpreters allow dynamic state machines that can be loaded, modified, or replaced at runtime.

Typically, these models are defined in a data format like SCXML (State Chart XML), a W3C standard.

Here is an example of our statemachine in SCXML:

<scxml version="1.0" initial="Off" xmlns="http://www.w3.org/2005/07/scxml">
  <datamodel>
    <data id="onCount" expr="0"/>
    <data id="isOn" expr="false"/>
  </datamodel>

  <state id="Off">
    <transition event="buttonPressed" target="On">
      <script>isOn = true;</script>
    </transition>
  </state>

  <state id="On">
    <onentry>
      <script>onCount = onCount + 1;</script>
    </onentry>
    <transition event="buttonPressed" target="Off">
      <script>isOn = false;</script>
    </transition>
  </state>

</scxml>

✅ Advantages:

❌ Disadvantages:


Choosing the Right Strategy

Goal/Constraint Recommended Strategy
Ultra-small, fast code Code-only (Switch/Case or Table)
Easy development & maintenance Library (Spring, Boost, RKH)
Runtime dynamic models Interpreter (SCXML engines)
Static embedded systems Code-only or lightweight library

In practice:


Summary

There is no single “best” way to implement a state machine — only the best way for your specific project.

Key questions to ask:

By understanding the trade-offs, you can choose the right approach and build reliable, elegant systems based on the timeless power of state machines.


Ready to continue? Head over to Chapter 8: Summary and Next Steps