Concepts / Timers, Keyboard Events, and State Machines

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.

  • Programming

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

Definition

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.

Light offlightIsOn is falseLight onlightIsOn is truebutton pressbutton press
When a button press arrives, which state does the light move to from each of its two starting states?

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.

Key point

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.

Wait for eventprogram idleRun handlermethod for this eventUpdate statevariablesnew values assignedRepaint displaydrawn from current stateevent arrivesreads and writespaint reads statereturn to waiting
After an event arrives, which steps run, and where does control return?

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

Worked example

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.

  1. 1
    Identify 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 of isLit when the tick arrives.

  2. 2
    Handle the first tick

    isLit is false when the first tick arrives. The handler checks the state, finds it false, and assigns true. The indicator is now lit.

  3. 3
    Handle the second tick

    The second tick is the same kind of event, but isLit is now true. The handler finds it true and assigns false. The indicator goes dark again.

  4. 4
    Compare 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.

Result

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.

Button pressidentical eventButton pressidentical eventLight turns onlightIsOn becomes trueLight turns offlightIsOn becomes falsestate is offstate is on
Given the same button press, what does the wall light do when it starts off and when it starts on?

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 like

    Thinking that a button press always turns the light on, because that is what the button does the first time.

    Why it fails

    A 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 instead

    Before 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 like

    Tracking the positions of objects in a game but forgetting whether the bomb is currently falling.

    Why it fails

    The 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 instead

    Ask 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 like

    Storing only a boolean for an explosion that lasts several frames.

    Why it fails

    A single true or false value cannot record how far into a multi-frame process the program is.

    Do this instead

    Add 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

EASY

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
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.