Skip to main content
deleted 655 characters in body; edited title
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

State pattern + C++ template == short and elegant hierarchical FSM solution?

C++11/g++ 4.8 update

If anybody is interested, inherited constructors from C++11 are a real game changer for the solution exposed here. I have just upgraded from g++ 4.6 and to 4.8, that has better support for C++11. I am so happy I did!

I am able to change the ugly

explicit LevelState(Machine &m, StateRef<LevelState> &state) :
    GenericState<Machine, LevelState>(m, state) {}

into the neat

using GenericState::GenericState;

Since a state machine can contain many abstract and concrete states, that makes the whole code much more readable.

The code below reflects this change.

Introduction

The code belowThis finds its origin in the following reflection.

  In their book from 1995, the so-called gang of four (GoF) described the state pattern. What they were actually telling us in their description, is that any object oriented language that implements dynamic polymorphism has an embedded finite state machine (FSM) engine. C++ is such a language, and the example code in the book is written in that language. Why then, do we have to use large frameworks, libraries and tools in order to implement state machines in C++?

Not so neat. I started to wonder if templates couldn't help me to parametrize the target state in ChangeState()ChangeState(). If the state had both a reference to the FSM and the ability to transform itself as a result of a transition, surely I would get a much simpler and cleaner syntax.

sillySilly state machine

As the code below testifies (public domain, use it as you wish, but don't blame me - compiles with g++ 4.6, C++11 switched on), I have managed to implement the state machine depicted above, in such a simple syntax, with the help of a 40-line state template that I have called GenericStateGenericState (genericstate.h, the rest is the state machine code):

  1. Entry and exit actions can be defined at any state level. Transition actions are programmed as regular instructions in the event handlers before the actual state transitions. There is, however, a difference with the UML in the order of execution: transition actions, exit actions (old state), entry actions (new state). The UML has exit, transition actions, entry. But mine is the same order as Miro Samek's model (http://www.state-machine.com/) - i.e. it is not uncommon and there is nothing wrong with it as long as it is consistent.
  2. Guards are regular "if" or "switch" statements in event handlers.
  3. Event parameters are regular event handler arguments. The event handler signature is free (and clutter-free).
  4. Composite states are implemented by applying the same model recursively. In the sate machine above, the state "Left" contains a "ColorState"ColorState virtual state that can be "Red" or "Blue". However, when going from "Left" to "Right", the exit action from the current color will not be executed (contrary to the UML semantics, but not a practical problem I believe).
  5. Orthogonal states are managed by letting the FSM have several virtual state members instead of just one ("LevelState"LevelState and "DirectionState"DirectionState in "Machine"Machine in the example).
  6. Access to the FSM members is given to all states through the FSM reference "m" (e.g. m.changedColor()m.changedColor()).

Please commentQuestions:

Output from the program

entering High
changed color
leaving High
entering Low
already Low
leaving Low
entering High
already High
unhandled event
changed color
unhandled event
changed color
entering High
changed color
leaving High
entering Low
already Low
leaving Low
entering High
already High
unhandled event
changed color
unhandled event
changed color

State pattern + C++ template == short and elegant hierarchical FSM solution?

C++11/g++ 4.8 update

If anybody is interested, inherited constructors from C++11 are a real game changer for the solution exposed here. I have just upgraded from g++ 4.6 and to 4.8, that has better support for C++11. I am so happy I did!

I am able to change the ugly

explicit LevelState(Machine &m, StateRef<LevelState> &state) :
    GenericState<Machine, LevelState>(m, state) {}

into the neat

using GenericState::GenericState;

Since a state machine can contain many abstract and concrete states, that makes the whole code much more readable.

The code below reflects this change.

Introduction

The code below finds its origin in the following reflection.

  In their book from 1995, the so-called gang of four (GoF) described the state pattern. What they were actually telling us in their description, is that any object oriented language that implements dynamic polymorphism has an embedded finite state machine (FSM) engine. C++ is such a language, and the example code in the book is written in that language. Why then, do we have to use large frameworks, libraries and tools in order to implement state machines in C++?

Not so neat. I started to wonder if templates couldn't help me to parametrize the target state in ChangeState(). If the state had both a reference to the FSM and the ability to transform itself as a result of a transition, surely I would get a much simpler and cleaner syntax.

silly state machine

As the code below testifies (public domain, use it as you wish, but don't blame me - compiles with g++ 4.6, C++11 switched on), I have managed to implement the state machine depicted above, in such a simple syntax, with the help of a 40-line state template that I have called GenericState (genericstate.h, the rest is the state machine code):

  1. Entry and exit actions can be defined at any state level. Transition actions are programmed as regular instructions in the event handlers before the actual state transitions. There is, however, a difference with the UML in the order of execution: transition actions, exit actions (old state), entry actions (new state). The UML has exit, transition actions, entry. But mine is the same order as Miro Samek's model (http://www.state-machine.com/) - i.e. it is not uncommon and there is nothing wrong with it as long as it is consistent.
  2. Guards are regular "if" or "switch" statements in event handlers.
  3. Event parameters are regular event handler arguments. The event handler signature is free (and clutter-free).
  4. Composite states are implemented by applying the same model recursively. In the sate machine above, the state "Left" contains a "ColorState" virtual state that can be "Red" or "Blue". However, when going from "Left" to "Right", the exit action from the current color will not be executed (contrary to the UML semantics, but not a practical problem I believe).
  5. Orthogonal states are managed by letting the FSM have several virtual state members instead of just one ("LevelState" and "DirectionState" in "Machine" in the example).
  6. Access to the FSM members is given to all states through the FSM reference "m" (e.g. m.changedColor()).

Please comment

Output from the program

entering High
changed color
leaving High
entering Low
already Low
leaving Low
entering High
already High
unhandled event
changed color
unhandled event
changed color

State pattern + C++ template

This finds its origin in the following reflection. In their book from 1995, the so-called gang of four (GoF) described the state pattern. What they were actually telling us in their description, is that any object oriented language that implements dynamic polymorphism has an embedded finite state machine (FSM) engine. C++ is such a language, and the example code in the book is written in that language. Why then, do we have to use large frameworks, libraries and tools in order to implement state machines in C++?

Not so neat. I started to wonder if templates couldn't help me to parametrize the target state in ChangeState(). If the state had both a reference to the FSM and the ability to transform itself as a result of a transition, surely I would get a much simpler and cleaner syntax.

Silly state machine

As the code below testifies (public domain, use it as you wish, but don't blame me - compiles with g++ 4.6, C++11 switched on), I have managed to implement the state machine depicted above, in such a simple syntax, with the help of a 40-line state template that I have called GenericState (genericstate.h, the rest is the state machine code):

  1. Entry and exit actions can be defined at any state level. Transition actions are programmed as regular instructions in the event handlers before the actual state transitions. There is, however, a difference with the UML in the order of execution: transition actions, exit actions (old state), entry actions (new state). The UML has exit, transition actions, entry. But mine is the same order as Miro Samek's model (http://www.state-machine.com/) - i.e. it is not uncommon and there is nothing wrong with it as long as it is consistent.
  2. Guards are regular "if" or "switch" statements in event handlers.
  3. Event parameters are regular event handler arguments. The event handler signature is free (and clutter-free).
  4. Composite states are implemented by applying the same model recursively. In the sate machine above, the state "Left" contains a ColorState virtual state that can be "Red" or "Blue". However, when going from "Left" to "Right", the exit action from the current color will not be executed (contrary to the UML semantics, but not a practical problem I believe).
  5. Orthogonal states are managed by letting the FSM have several virtual state members instead of just one (LevelState and DirectionState in Machine in the example).
  6. Access to the FSM members is given to all states through the FSM reference "m" (e.g. m.changedColor()).

Questions:

Output

entering High
changed color
leaving High
entering Low
already Low
leaving Low
entering High
already High
unhandled event
changed color
unhandled event
changed color
deleted 80 characters in body
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

Thanks in advance.

Talk is cheap, here comes the code

genericstate.hgenericstate.h

machine.hmachine.h

machine.cppmachine.cpp

main.cppmain.cpp

Thanks in advance.

Talk is cheap, here comes the code

genericstate.h

machine.h

machine.cpp

main.cpp

genericstate.h

machine.h

machine.cpp

main.cpp

Added tag
Link
nilo
  • 791
  • 2
  • 6
  • 15
deleted 3 characters in body
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
C++11/g++4.8 update
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
Removed section about flyweight and runtime cost, since it was as silly as my state machine :-)
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
Added a section about flyweight and runtime cost
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
Added a section about flyweight and runtime cost
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
edited body
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
added 1 characters in body; Post Made Community Wiki
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
deleted 1 characters in body
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
deleted 5 characters in body; deleted 9 characters in body
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
added 15 characters in body
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
added 16 characters in body
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
Clearified the text and made the example both shorter and more relevant
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
Clearified the text and made the example both shorter and more relevant
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
added 94 characters in body
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
added 94 characters in body
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
added 3599 characters in body
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading
Tweeted twitter.com/#!/StackCodeReview/status/430061412690722817
Source Link
nilo
  • 791
  • 2
  • 6
  • 15
Loading