What is a pure function?

One of the first things you will encounter when learning functional programming is the idea of pure functions. Functional programming is all about combining small pieces of code together to form a large vision, and pure functions help us do just that.
I'm going to use javascript in this article because its the most accessible and popular language in the world. Meaning you can most likely take these ideas and start using them immediately.
A Pure Function
A function is pure
if it passes two simple tests:
- Given the same input, it will always return the same output.
- It has no side effects.
Let’s take a look these two rules.
Given the same input, it will always return the same output
Here's a pure function:
1const cowSay = (phrase) => `The cow says ${phrase}`;
We say cowSay
is pure because if you call it with the string 'moo'
, it will always return the string 'The cow says moo'
, no matter how many times you call it.
1for (let i = 1; i =< 100; i++) {2 const says = cowSay("moo")3 console.log(`${i}: ${says}`)4}5// Output6// 1: The cow says moo7// 2: The cow says moo8// 3: The cow says moo9// 4: The cow says moo10// 5: The cow says moo11// 6: The cow says moo12// ... and so on up to 100
A more complex example that calculates the price of items in an order:
1const order = {2 items: [3 { name: "bandage", price: 1.25 },4 { name: "coffee", price: 3.4 },5 { name: "board game", price: 12.99 },6 ],7};8
9const calculateTotal = (items) => 10 items.reduce((item, acc) => acc + item.price, 0); 11
12const total = calculateTotal(order.items);13
14console.log(`Your total is ${total}`); // Your total is 17.64
calculateTotal
is pure because if you give it the same items array 1 million times, it always will return the same total
It has no side effects
A function has a side effect if it modifies state outside of itself.
These three functions below (double
, addOne
, log
) all perform side-effects:
1let state = 2;2
3// Effect-ful4const double = () => {5 state = state * 2;6};7
8const addOne = () => {9 state = state + 1;10};11
12const log = () => console.log(state);13
14// Program15log(); // 216double();17addOne();18log(); // 519
20double();21double();22log(); // 20
Take note that the log
function above performs a side-effect as well, it logs to the console. The console is a stateful output device who’s state is what has been displayed to the user.
This immediately begs the question:
”Where do we put side effects?!? This program works perfectly fine, why would I change it?"
There are a couple answers to these questions, but the easiest is to just clearly separate them.
Let’s re-write the example above by separating side-effect and pure functions:
1let state = 2;2
3// Effect-ful4function change(newState) {5 state = newState;6}7
8function log() {9 console.log(state);10}11
12// Pure13const add = (number) => number + 1;14
15const double = (number) => number * 2;16
17// Program18log(); // 219change(addOne(state));20change(double(state));21log(); // 522
23change(double(state));24change(double(state));25log(); // 20
Now, the logic of the program (pure functions) is separated from the things that change state (side-effect functions). We do this because side-effects are often un-predictable. They rely on external systems that we don’t control. If we isolate our side effects, we can create programs that are more predictable.
Here's a great answer on Stack Overflow if you want to go deeper into managing side-effects.
Conclusion
I hope that was helpful! Pure functions have helped me write cleaner code and understand my code better when it comes time to debug my applications. Learning functional programming can be overwhelming. Hopefull this was helpful to you in understanding this small part of functional programming.
About the Author
Hi đź‘‹ I'm Tyler. I'm a software engineer with a passion for learning new things. I love solving hard problems and simplifying them down to their pieces. Presently residing in Utah with my two girls and beautiful wife.