By Yazeed Bzadough
Pure functions are the atomic building blocks in functional programming. They are adored for their simplicity and testability.
This post covers a quick checklist to tell if a functionās pure or not.

The Checklist
A function must pass two tests to be considered āpureā:
- Same inputs always return same outputs
- No side-effects
Letās zoom in on each one.
1. Same Input => Same Output
Compare this:
const add = (x, y) => x + y;
add(2, 4); // 6
To this:
let x = 2;
const add = (y) => {
x += y;
};
add(4); // x === 6 (the first time)
Pure Functions = Consistent Results
The first example returns a value based on the given parameters, regardless of where/when you call it.
If you pass 2 and 4, youāll always get 6.
Nothing else affects the output.
Impure Functions = Inconsistent Results
The second example returns nothing. It relies on shared state to do its job by incrementing a variable outside of its own scope.
This pattern is a developerās nightmare fuel.
Shared state introduces a time dependency. You get different results depending on when you called the function. The first time results in 6, next time is 10 and so on.
Which Versionās Easier to Reason About?
Which oneās less likely to breed bugs that happen only under certain conditions?
Which oneās more likely to succeed in a multi-threaded environment where time dependencies can break the system?
Definitely the first one.
2. No Side-Effects

This test itself is a checklist. A few examples of side-effects are
- Mutating your input
console.log- HTTP calls (AJAX/fetch)
- Changing the filesystem (fs)
- Querying the DOM
Basically any work a function performs that isnāt related to calculating the final output.
Hereās an impure function with a side-effect.
Not So Bad
const impureDouble = (x) => {
console.log('doubling', x);
return x * 2;
};
const result = impureDouble(4);
console.log({ result });
console.log is the side-effect here but, in all practicality, it wonāt harm us. Weāll still get the same outputs, given the same inputs.
This, however, may cause a problem.
āImpurelyā Changing an Object
const impureAssoc = (key, value, object) => {
object[key] = value;
};
const person = {
name: 'Bobo'
};
const result = impureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
The variable, person, has been forever changed because our function introduced an assignment statement.
Shared state means impureAssoc's impact isnāt fully obvious anymore. Understanding its effect on a system now involves tracking down every variable itās ever touched and knowing their histories.
Shared state = timing dependencies.
We can purify impureAssoc by simply returning a new object with our desired properties.
Purifying It Up
const pureAssoc = (key, value, object) => ({
...object,
[key]: value
});
const person = {
name: 'Bobo'
};
const result = pureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
Now pureAssoc returns a testable result and weāll never worry if it quietly mutated something elsewhere.
You could even do the following and remain pure:
Another Pure Way
const pureAssoc = (key, value, object) => {
const newObject = { ...object };
newObject[key] = value;
return newObject;
};
const person = {
name: 'Bobo'
};
const result = pureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
Mutating your input can be dangerous, but mutating a copy of it is no problem. Our end result is still a testable, predictable function that works no matter where/when you call it.
The mutationās limited to that small scope and youāre still returning a value.
Deep-Cloning Objects
Heads up! Using the spread operator ... creates a shallow copy of an object. Shallow copies arenāt safe from nested mutations.
Thank you Rodrigo FernĆ”ndez DĆaz for bringing this to my attention!
Unsafe Nested Mutation
const person = {
name: 'Bobo',
address: { street: 'Main Street', number: 123 }
};
const shallowPersonClone = { ...person };
shallowPersonClone.address.number = 456;
console.log({ person, shallowPersonClone });

Both person and shallowPersonClone were mutated because their children share the same reference!
Safe Nested Mutation
To safely mutate nested properties, we need a deep clone.
const person = {
name: 'Bobo',
address: { street: 'Main Street', number: 123 }
};
const deepPersonClone = JSON.parse(JSON.stringify(person));
deepPersonClone.address.number = 456;
console.log({ person, deepPersonClone });

Now youāre guaranteed safety because theyāre truly two separate entities!
Summary

- A functionās pure if itās free from side-effects and returns the same output, given the same input.
- Side-effects include: mutating input, HTTP calls, writing to disk, printing to the screen.
- You can safely clone, then mutate, your input. Just leave the original one untouched.
- Spread syntax (
ā¦syntax) is the easiest way to shallowly clone objects. JSON.parse(JSON.stringify(object))is the easiest way to deeply clone objects. Thanks again Rodrigo FernĆ”ndez DĆaz!
My Free Course
This tutorial was from my completely free course on Educative.io, Functional Programming Patterns With RamdaJS!
Please consider taking/sharing it if you enjoyed this content.
Itās full of lessons, graphics, exercises, and runnable code samples to teach you a basic functional programming style using RamdaJS.
Thanks for reading! Until next time.