Timers, Keyboard Events, and State Machines
A state machine is something that has a state and can change state in response to events or inputs, and its response to an event depends on the state it is in when the event occurs.
Same Press, Different Result
Imagine a button in a program that you press repeatedly. Sometimes pressing it opens a menu, and at other times the same press closes it. Nothing about the press itself has changed. What has changed is the program's memory of what it is currently doing. Computer scientists have a name for anything that remembers a condition of its own and changes that condition when something happens to it: a state machine.
As you read the rest of this article, keep one question in mind. When an event arrives, what information must the program consult before it decides how to respond? The answer to that question is the central idea of this article, and it applies equally to a light switch, a game, a timer, or a graphical user interface.
What a State Machine Is
A state machine is something that has a state and can change state in response to events or inputs. Its response to an event depends on the state it is in when the event occurs.
Two parts of that definition matter most. The first is the state, which is the remembered condition of the thing. The second is the event, which is something that arrives from outside, such as a key press, a mouse action, or a timer firing. A state machine does not respond to an event in isolation. It responds to the event together with whatever state it is already in. The same event can therefore produce different results at different times, and the difference is entirely explained by the state.
To practice the idea outside the source's own examples, consider a simple wall light controlled by a single button. The light has two states, on and off, and it has one kind of event: a button press. The state can be stored in a boolean variable named lightIsOn. The response to a press depends on that variable. If the light is off, a press turns it on. If the light is on, a press turns it off. The button is identical in both cases. Only the stored state differs.
Tracing the Two-State Light
The diagram below shows the wall light as a state machine. Each box is a state, and each arrow is a response to an event. Both arrows carry the same label, which tells you that the event is identical in both cases. Only the starting state differs, and that difference alone determines where the light ends up.
Follow the trace step by step. Start with the light off, so lightIsOn holds false. A button press arrives. The machine checks the state, finds it off, and follows the arrow to the on state, so lightIsOn becomes true. Now take the same button press while the light is on. The event is identical, but the state is not. The machine follows the other arrow and turns the light off. Nothing in the button itself distinguishes the two cases. The state variable is what makes the difference.
State Variables in an Object
In an object-oriented program, the information stored in an object's instance variables is called the state of that object. The state is the collection of values that describe the object at a given moment, and those values determine how the object looks or behaves.
Two consequences follow. First, when one of the object's methods is called, the action the object takes can depend on its state. The method can read the instance variables and decide what to do based on what it finds there. Second, the state can change. The method can assign new values to the instance variables, so the next call may behave differently from the last one. Reading and writing the same instance variables is how an object remembers across calls.
If you can name an object's states and the events that move it between them, you have a clear plan for the methods that the class needs. This viewpoint is especially useful when designing classes.
Why Event-Driven Programs Are Built Around State
The state machine viewpoint is especially useful in event-oriented programming, the style required by graphical user interfaces. In such a program, nothing runs from top to bottom in one fixed sequence. Instead, the program waits for events, such as key presses or mouse actions, and each event triggers a handler that runs in response.
Because a handler runs at an arbitrary moment, the program must know its own condition whenever an event arrives. The diagram below shows the cycle that repeats for the life of the program. The program waits, an event arrives, a handler runs and updates the state variables, the display is repainted from that state, and then the program returns to waiting.
The source contrasts this approach with top-down, step-wise refinement, which it says does not apply to the overall design of an event-oriented program. Rather than planning one long sequence of steps, you plan a collection of states, the events that can occur, and the responses that depend on each combination. When building a GUI program, the source suggests asking several design questions: what information about state must be tracked, which events can change that state, how the response to a given event depends on the current state, whether the appearance of the interface should change to reflect a state change, and how the drawing code should take the state into account.
Same Event, Two Starting States
Tracing a timer tick through a blinking indicator
A small indicator has a state variable isLit, which is a boolean. A timer fires an event every second, and the handler for that event is responsible for changing isLit. Trace what happens for two consecutive ticks when isLit starts as false.
- 1Identify the state and the event
The state is the boolean
isLit. The event is a timer tick. The handler's response depends on the value ofisLitwhen the tick arrives. - 2Handle the first tick
isLitis false when the first tick arrives. The handler checks the state, finds it false, and assigns true. The indicator is now lit. - 3Handle the second tick
The second tick is the same kind of event, but
isLitis now true. The handler finds it true and assigns false. The indicator goes dark again. - 4Compare the results
The identical tick produced opposite outcomes. The only thing that differed was the value stored in the state variable at the moment the event arrived.
The same timer tick turns the indicator on the first time and off the second time, because the state variable differs between the two arrivals.
The comparison above shows the point of this whole article in one picture. The event column is identical in both groups. The outcome column differs. Tracing the machine means naming the starting state first, then following the transition that state allows for the event that arrived.
Mistakes Beginners Make With State
Common mistake Assuming the event alone determines the response
What it looks likeThinking that a button press always turns the light on, because that is what the button does the first time.
Why it failsA state machine's response depends on the state it is in when the event occurs. The same press can lead to different results.
Do this insteadBefore predicting a response, name the current state and then follow the transition that state allows for the event.
Common mistake Treating state as only the obvious variables
What it looks likeTracking the positions of objects in a game but forgetting whether the bomb is currently falling.
Why it failsThe source shows that state can be less obvious than it first appears. A falling-or-not difference is state even though it is not a position.
Do this insteadAsk what can make the same event behave differently, and store that condition in a variable.
Common mistake Using one flag where a count is needed
What it looks likeStoring only a boolean for an explosion that lasts several frames.
Why it failsA single true or false value cannot record how far into a multi-frame process the program is.
Do this insteadAdd an integer, such as a frame counter, and remember that it matters only while the process is in progress.
Common mistake Writing state variables without reading them in the display code, so the interface never reflects the change
Practice Tracing a State Change
A wall light starts with lightIsOn set to true. Two button presses arrive in sequence, and then a third. Before reading the answer, predict the final value of lightIsOn and explain which state each press encountered.
Hints
- Name the state before each press, then apply the transition that state allows.
- Two presses in a row return the machine to where it started.
- Remember that the event is identical each time, so only the state changes the outcome.
What do you think happens?
The light is on and a button press arrives. What happens to lightIsOn?
Reveal answer
lightIsOn becomes false, and the light turns off.
The same press that turns an off light on turns an on light off. The state, not the button, determines the result.
Key Takeaways
- A state machine has a state and changes that state in response to events, and its response to an event depends on the state it is in when the event occurs.
- In an object, the state is held in instance variables, and methods both read those variables to decide what to do and assign new values to change what happens next.
- Event-oriented programs such as GUIs wait for events, dispatch each one to a handler, and organize their design around the states, the events that change them, and how responses depend on the current state.
- The same event can produce different results in different states, so tracing a machine means naming the current state before applying the transition for the event that arrived.
- State can be less obvious than it first appears, and some state variables, such as a frame counter, matter only under particular conditions.