Understanding Pure Functions: A Guide to Predictable Coding
Written on
Chapter 1: The Essence of Pure Functions
When discussing functional programming, the concept of pure functions frequently arises. These functions are foundational within this paradigm but can also be found across various programming styles. Their primary advantage lies in enhancing simplicity and predictability in code.
You might already be utilizing pure functions without realizing it. Upon reviewing the examples provided, you may think, “That’s simply a function.” While you're correct, grasping the characteristics that define pure functions will deepen your understanding of their importance. So, what exactly constitutes a pure function?
To qualify as a pure function, two main criteria must be satisfied:
- Consistent Output for Identical Input
- Absence of Side Effects
Consistent Output for Identical Input
For instance, if you input the number 3 into a pure function and receive 30 as a result, you should consistently get 30 whenever you input 3.
function multiplyByTen(num) {
return num * 10;
}
If I call this function with an input of 2, it should yield 20 every time.
multiplyByTen(1); // 1 * 10 = 10
multiplyByTen(2); // 2 * 10 = 20
multiplyByTen(3); // 3 * 10 = 30
Notice the purity!
Inconsistent Output for Identical Input
If a function fails to be pure, it can produce varying outputs for the same input. For example, if I input 3 and get 30 one time, I might receive 15 the next.
let multiplier = 10;
function multiplyByMultiplier(num) {
return num * multiplier;
}
multiplyByMultiplier(3); // 3 * 10 = 30
multiplier = 5;
multiplyByMultiplier(3); // 3 * 5 = 15
The function above is impure because it yields inconsistent results for the same input. Such behavior can lead to frustrating bugs, so it’s vital to maintain output consistency.
No Side Effects
A function is said to have side effects if executing it alters the state outside of its own scope.
function multiplyByTen(num) {
return num * 10;
}
This function is pure because it solely performs a calculation and returns a result without affecting any external state.
With Side Effects
In contrast, if a function modifies an external variable, it is no longer pure.
let result;
function multiplyByTen(num) {
result = num * 10;
return result;
}
In this updated version, we store the result of multiplyByTen in a variable outside the function. While it meets the first criterion, it introduces a side effect by changing the value of result each time the function is invoked.
This approach may lead to unpredictable code behavior, making debugging more challenging.
class Person {
private _name;
get name() {
return this._name;}
set name(value) {
this._name = value;}
}
The setter in this class isn’t pure due to its side effect. However, since the side effect is encapsulated within the class, it remains manageable. If applied indiscriminately elsewhere, it could complicate debugging and testing.
Testing Pure Functions
Because pure functions consistently produce the same output for the same input and have no side effects, they are straightforward to test.
test('given 3, return 30', () => {
const actual = multiplyByTen(3);
expect(actual).toBe(30);
});
While this is a simple example, testing more complex pure functions is just as easy, albeit with more cases to cover.
Conclusion
Ultimately, the focus is on simplicity and predictability. Pure functions are straightforward, predictable, and highly testable. Although there may be exceptions allowing for side effects, these are typically confined to encapsulated code, maintaining overall clarity and manageability.
Adopting pure functions can lead to a more enjoyable coding experience, reducing cognitive load and minimizing debugging worries.
The first video, "Learn Pure Functions In 10 Minutes," provides a concise overview of what pure functions are and why they matter in programming.
The second video, "What are Pure Functions and Side Effects in JavaScript?", dives deeper into the characteristics of pure functions and the implications of side effects.