What are pure functions?

If you've started to learn React or Redux recently you've probably heard of pure functions. In this post, I'll be breaking down pure functions to their most basic properties and providing some advice for testing.

Back to Basics

One of the first functions people learn to write is the add(x, y) function. It simply takes in two parameters that are numbers and returns the sum. Let's write it out:

const add = (x, y) => x + y;

In the case that x = 1 and y = 2 we know the return value will be 3.

When we're talking about pure functions we're curious about what influences the return value. From our example above, the return value (3)  is a direct result of the parameters (x and y).

No matter how many times you can add(1, 2) the return value will always be 3. It doesn't matter if it's Monday at noon or Wednesday at midnight, the return value will always be the same.

The only way to change the return value is to change the parameters; in that sense, the function: const add = (x, y) => x + y; is considered to be a pure function.

Rules for Pure Functions

Here are the two most basic rules for pure functions:

  1. The function cannot modify or rely on code out of its scope.
  2. The function must always return the same value for the same parameters.

In the case of const add = (x, y) => x + y; we can see that there is never a point where the function is trying to use code beyond its scope. That means we don't have something like:

const x = 1; 

const add(y) => x + y; 

In this example, x is defined outside of the scope of the add() function and thus if another operation changed the value of x it would map to different return values for add(y). In this case, add(y) is considered an impure function.

So, what are some other examples of impure functions?

Here's a classic example that requires on some external data:

const greetingOfTheDay = (name) => {
  const date = new Date();
  const dateString = date.toDateString();
  return `Welcome ${name} today is ${dateString};

When we call the new Date() constructor, it's pulling a value from the operating system that we can't see. This violates the first rule of pure functions. It's not as obvious that it's pulling from outside the scope like it was in the add(y) example; but we know based on the implementation of new Date() that it requires some stateful information from outside of the function.

Testing & Maintaining Pure Functions

One of the benefits of pure functions is that they're much easier to test. Instead of writing complicated functions riddled with side effects, your tests strictly evaluate the behavior of a function and its parameters.

Granted, you could write a function f(x: state) with some very complicated state type and still have a hard time writing tests... but that's a different story! The idea is that your functions take in only what they need, and provide an accurate and useful return value.