Back to writing
Software

Pure Functions

Overview

A pure function is a function whose output is determined only by its input. In other words, it is an idempotent function that always returns the same result when given the same input.

This property can be compared to a very simple machine.

  1. Input: the only place where data enters
  2. Engine (function body): calculates using only the input data
  3. Output: the only place where the result is returned

This structure creates a state where the function's output is determined only by its input.

Pure functionx = 3x = 3x = 3f(x)x × 2666same inputevery timealways same outputdoes not read or mutate external stateImpure functionexternal: countx = 3x = 3g(x)x + count++reads & mutates45same input,different resultdepends on & mutates external stateTwo core rules of pure functions① Referential transparencyf(3) always returns the same valuecall can be replaced by its result② No side effectsI/O, global vars, DB writes NGzero impact on the outside worldBenefits of pure functionsEasy to test · Safe to parallelize · Memoizable · Easy to debugExamples of side effects (avoided in pure functions)· console.log() calls (I/O)· Mutating global variables or objects· HTTP requests, DB writes, file operations

Rules of Pure Functions

A pure function has two important properties.

No side effects

  • Any interaction with the outside world during function execution, other than returning a value, is called a side effect
  • A function with side effects is impure, for example rewriting a global variable or throwing an exception

Referential transparency

  • Referential transparency means that replacing an expression with its evaluated result does not change the behavior of the entire program
  • Example: replacing f(x) + f(x) with 2 * f(x) is safe

Sample Code

Pure functions:

# Pure def add(a, b): return a + b # Pure def multiply(x, y): return x * y # Pure (mathematical) def square(n): return n * n

Impure functions:

# Impure - uses external state counter = 0 def increment(): global counter counter += 1 return counter # Impure - side effect (printing) def say_hello(name): print(f"Hello, {name}!") # side effect # Impure - depends on current time import datetime def get_current_year(): return datetime.datetime.now().year # Impure - mutates input def add_to_list(lst, item): lst.append(item) # mutates the original list return lst

Why It Matters

Pure functions are essential for maintainable and extensible implementations.

  • Easier debugging: the cause of a bug is guaranteed not to be outside the function
  • Easier testing: no need to prepare external state or mocks
  • Easier parallelization: data races caused by side effects do not occur
  • Memoization becomes possible: because the same input always produces the same output, results can be cached

References