State: How Change in Dynamic Systems Effect Output

stateful system illustration overcoded

State is a term used in computer science that describes the current information of a system. A system is deemed “stateful” if it has the capacity to remember information from proceeding operations and user interactions. Examples of stateful systems include automata, computer programs, and digital circuits.

That definition is analogous to the more formal version provided by Wikipedia. It’s my opinion that such formal explanations often lack utility. State, as I’ve come to recognize it, is one of those topics that are so fundamental and broadly applicable that definitions are often tricky. That is; one can understand state easily by example but putting formal words to it is tough. With that in mind, let’s consider some examples of stateful systems.

A Social Media Application

Social media applications typically allow the creation of user profiles. Let’s say we have an application called FaceBox (an obvious knock-off) that displays a list of all current users on the homepage. Fortunately, there are only 5 users currently.

When we log on we see a list of these 5 user profiles as deemed fit by the application’s front-end team. This is a visual representation of the application’s current data—which can be recognized as its current State. Here’s where things get tricky though.

The application’s State can be affected by any number of things including user interaction, network conditions, data corruption, or even inconsistencies in hardware running the system. At some point, one has to draw a line in the sand to determine what degree of state one is considering. Here are some examples that could change the state of our fictitious social media application:

  1. A user updates their profile picture resulting in a slightly different homepage;
  2. A developer updating the CSS resulting in a slightly different homepage;
  3. A user clicking the refresh button on their browser bring the most recently updated profiles to the top of the homepage;
  4. A slowing of the network triggers a timeout in an asynchronous API call to a dynamic data displaying recent news headlines on the homepage;

These changes are but a few of many that could cause a state change in the FaceBox application. Modern systems, especially web-facing user-interacting ones, have a myriad of possible streams to initiate a state change. Extracting a definition of state can still be difficult here. Let’s consider an example with slightly more basic and fundamental components.

Objects & Functions

Functional programming can be defined as a declarative system by which all actions are purely deterministic and mathematical. That means, given an identical input, a system will produce an identical output every time. Simply put; there is no state.

Imperative programming can be defined as an approach by which a series of statements are used to alter the state of a program. This would include the updating of variables, associations, and even dependencies in an environment such as those provided by modern object-oriented programming languages.

Consider the following Stateful class, having both functional and imperative methods:

public class Stateful {

    // Declare a magic value
    int magicNumber;

    /**
     * Basic constructor requiring an integer to be used as the magic number.
     * @param a int - value to be used as the object's magic number.
     */
    public Stateful(int a){
        this.magicNumber = a;
    }

    /**
     * Returns the current value used as the objects magic number
     * @return int - an integer value
     */
    public int getMagicNumber() {
        return magicNumber;
    }

    /**
     * Updates the current value used as the object's magic number
     * @param magicNumber int - the value to use during update.
     */
    public void setMagicNumber(int magicNumber) {
        this.magicNumber = magicNumber;
    }

    /**
     * A simple function that calculates the sum of two integer values.
     * @param a int - the first integer
     * @param b int - the second integer
     * @return int - the sum of a and b, as an integer.
     */
    public static int addIntegers(int a, int b){
        return a + b;
    }

    /**
     * A simple function that calculates the sum of two integers and
     * the current value used by the object as its magic number.
     * @param a int - the first integer
     * @param b int - the second integer
     * @return int - the sum of a + b + magicNumber, as an integer.
     */
    public int addIntegersStatefully(int a, int b){
        return a + b + getMagicNumber();
    }
}

In this example code, the addIntegers method is static (a sign of being functional) and the addIntegersStatefully is non-static (a sign of being imperative). These two functions can be further contrasted in that the use of addIntegersStatefully requires an object of type Stateful to be instantiated whereas the addIntegers method can be accessed without such dependency. Consider the following code illustrating a possible usage of this class:

/**
 * Driver class to illustrate the functionality of Stateful, its methods,
 * and how they represent a non-Stateful (functional) and Stateful (imperative)
 * design.
 */
public static void main(String[] args) {

    // Define our integers
    int a = 6;
    int b = 9;

    // Test functional method
    // Note use of static method here.
    System.out.println("a + b = " + Stateful.addIntegers(a, b));

    // Test imperative method
    // Note use of object instantiation here, with specified magic number.
    Stateful stateObject = new Stateful(3);
    System.out.println("Current Magic Number = " + stateObject.getMagicNumber());
    System.out.println("a + b = " + stateObject.addIntegersStatefully(a, b));

    // Change the magic number
    stateObject.setMagicNumber(6);
    System.out.println("Current Magic Number = " + stateObject.getMagicNumber());

    // Test functional method again
    System.out.println("a + b = " + Stateful.addIntegers(a, b));

    // Test imperative method again
    System.out.println("a + b = " + stateObject.addIntegersStatefully(a, b));
}

Let’s walk through some of this code to illustrate the key portions demonstrating state.

Using a Static Method (functional)

System.out.println("a + b = " + Stateful.addIntegers(a, b)); 

In this line, we are displaying to the console the result of a simple a + b summation function. This line uses a static method, negating our need to have instantiated a Stateful object prior. Such use cases are strong indicators of aspects of a program that do not have state.

That is; provide the system with the same input and one will get the same output each time. To solidify this concept consider re-running this line multiple times: the output will always be the result of the a + b values (3 & 6) defined just above it.

Using a Bound Method (imperative)

System.out.println("a + b = " + stateObject.addIntegersStatefully(a, b))

In this line, we are displaying to the console the result of a simple a + b summation as well, but this time we’re doing so via a method bound to the stateObject instance of our Stateful class. Such use cases hint at the involvement of state such that our output will now be subject to changes in the state of our stateObject instantiation.

That is; changes in the stateObject instantiation may alter the output of the addIntegersStatefully method, even when given identical input (our a & b variables.) In the case of this particular object, we know that the instances magicNumber will be added in succession with the supplied arguments a & b—a change in that number (representing our object’s state) will alter the output.

Example Output

With a brief understanding of how our Stateful object is designed, we can distill some meaning from seeing it in action. That is, we can understand how the state of the object influences the output in some cases. The code above generates the following output:

Value of a = 6
Value of b = 9
a + b = 15
Current Magic Number = 3
a + b = 18
Current Magic Number = 6
a + b = 15
a + b = 21

Note that on line 3 our program adds the values of a + b (6 + 9) and returns the value of 15. We wouldn’t actually need a method for this as Java (and any other programming language) provide built-in functions for simple mathematical operations like this.

On line 5, after announcing our magic number of 3, we use the addIntegersStatefully and produce an output of 18, which represents a + b + 3; a value influenced by the state of our program.

On line 6, the value of the magicNumber variable has been changed from 3 to 6.

Line 7 reflects the output generated having used the addIntegers method again, which ignores any state of our stateFul object. As expected, identical output is produced from that prior to updating the magicNumber variable.

Line 8 is where the magic happens. This number reflects the added value of 3 that has been added to our original magicNumber value of 3. This is reflected in our final calculated output of 21 (15 + 6 instead of 15 + 3) and represents the impact of our object’s state on the resulting output given identical input.

Note: The complete code from this example is available on GitHub here.

Final Thoughts on State

State is a powerful concept in computer science used to describe the dynamism of a wide range of systems. Whether one is working on a hobby project, helping to engineer a large-scale application, or simply conceptualizing analogs of the digital world found in the natural world—keeping in mind the concept of state is useful. I hope that the examples here have helped to illustrate state in a way that is enlightening and helpful!

Zαck West
Full-Stack Software Engineer with 10+ years of experience. Expertise in developing distributed systems, implementing object-oriented models with a focus on semantic clarity, driving development with TDD, enhancing interfaces through thoughtful visual design, and developing deep learning agents.