1

I have been doing a lot of thinking lately about the implications of event-based/responsive programming and UML statecharts.

I believe my thinking up to this point has been flawed. Take, for example, a toggle button/switch. It has an internal state: pressed or released. It also generates events: press and release. The events represent the transitions between states. Up until now, if I were to design a state machine that "reacted" to the button's state changes, but I needed a particular transition to be conditionally based upon the current state of the button, I would "query" the internal state of the button as part of a conditional transition/pseudostate (e.g., if the button were a class, the state machine would directly call button.state() before making its transition).

I now think that this is flawed approach because it exposes the internal state of the button, couples the other state machine to an implementation (event if it may be abstract) of the button (rather than just reacting to its events), and it "mixes metaphors" by being reactive (to events) while simultaneously being sequential (blocking) programming. This problem becomes more pronounced when the process of "querying" the internal state of something on which to make a decision is not so trivial (or, as mentioned in the book "Practical Statecharts in C/C++", impossible if, for example, you are trying to "view" the state of a quantum particle; the very act resulting in the state being affected).

With that discovery, I am trying to come up with other options that are truly reactive (i.e., based solely upon events).

As an example, suppose I want to design a state machine with 3 states: A, B, and C. It will handle 4 different events: B1_PRESS, B1_RELEASE, B2_PRESS, B2_RELEASE (i.e., events from two toggle buttons). If in state A, B1_PRESS transitions to state B. If in state B, B1_RELEASE transitions to state A. If in state A or B, B2_PRESS transitions to state C. However, when in state C, B2_PRESS transitions either to state A (if B1 is not pressed) or B (if B1 is pressed). In other words, B2 has higher priority than B1 in determining the state.

Option 1

Introduce an extended state variable used to store the current state of B1 based upon the events it produces. Then use a conditional/choice pseudostate to transition based upon this extended state variable.

option 1 state machine

The problems I have with this option are a) I have to use an extended state variable and b) The state of B1 is now technically stored twice: once in the button itself and once in my state machine. This might get pretty messy if I need to add more states and events.

Option 2

Defer the B1_PRESS and B1_RELEASE events while in state C.

option 2 state machine

This option is cleaner in notation than option 1. It also doesn't add any extended state. The problem I have with this option is that, if while in state C the state of B1 does change, state B is still "temporarily" entered when exiting state C but before the deferred B1_RELEASE event is processed. So, if the ENTER event of state B does some work, it will be wasted (or could cause weird problems).

Are there other options I have not considered? Is my original "revelation" about trying to work with events only reasonable?

2 Answers 2

3

Neither of your options correctly captures the stated sequence of events. For that, state C needs to remember from which state you entered. This can be done with a nested statemachine, like this:

enter image description here

3
  • This is really a different way of thinking for me. So essentially, you are adding an additional state to represent the "extended state" of the first button. And because of the hierarchy of states, C1 and C2 just handle the transitions while C (the parent) does the real work like before. Mar 8 at 17:26
  • 1
    I'm working how well this method scales if, for example, I add another button (B3) and another state D where being in state D due to B3 "takes priority" (in the same way B2 causes the transition to C as the priority). In other words, does it suffer from "combinational explosion?" Mar 8 at 18:03
  • 1
    @PatrickWright, it can indeed result in a combinatorial explosion. If the requirements are expressed in terms of the button state, I would quite quickly go back to querying the button's state instead of deriving that from the events. Mar 9 at 6:57
2

To decouple statemachines you could discriminate between signals and events. A statemachine sends signals which can be received by a second statemachine. The receipt of a signal is an event which triggers a transition (to use correct UML terminology). Possible event types are signals, calls, the passing of time and a state change.

As a concrete example for the way in which I would use these concepts to decouple state machines I'll use the example of an entry access system. The system comprises of a button which opens a door. When someone wants to enter the building he or she presses the button, the door starts opening till it's opened and after some time starts closing until it is closed again.

enter image description here

The Button state machine sends signals which are received by the Door statemachine. That statemachine can be unaware of the source of the signals it receives.

In an implementation of this system I would use interfaces to describe the experienced behaviour of Button and Door in terms of signals and events. That would allow to replace the button by e.g. a motion detector and the door by e.g. a light.

2
  • Just to clarify, the caret (^) symbol in UML means an output event correct? Mar 12 at 13:11
  • Well, to use the correct terminology, it's not an output event but it indicates the sending of a signal. The receipt of a signal is an event.
    – JosF
    Mar 12 at 13:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.