Pure function
In computer programming, a function may be considered a pure function if both of the following statements about the function hold:
- The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices (usually—see below).
- Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices (usually—see below).
The result value need not depend on all (or any) of the argument values. However, it must depend on nothing other than the argument values. The function may return multiple result values and these conditions must apply to all returned values for the function to be considered pure. If an argument is call by reference, any parameter mutation will alter the value of the argument outside the function, which will render the function impure.
Contents
Examples
Pure functions
sin(x)
, returning the sine of a number xlength(s)
, returning the size of a string sencrypt(k,d)
, running a deterministic encryption algorithm on a piece of data d using a key k
Impure functions
- Any function that uses a non-local variable is potentially impure. I.e., if there are any free variables in the function definition. For example
inc(x): x + a
returns the value ofx
incremented by the free variablea
, and thus depends on the value ofa
. - A function that returns the current day of the week is impure because at different times it will yield different results—it refers to some global state.
random()
is impure because each call potentially yields a different value. This is because pseudorandom generators use and update a global "seed" state. If we modify it to take the seed as an argument, i.e.random(seed)
; thenrandom
becomes pure, because multiple calls with the same seed value return the same random number.printf()
is impure because it causes output to an I/O device as a side effect.
Pure expressions
Pure functions are required to construct pure expressions. Constant expressions are pure by definition. An expression consisting of a function subexpression applied to one or more argument subexpressions is pure if both these statements about the subexpressions hold:
- The function and argument subexpressions are pure expressions.
- The function subexpression yields a pure function.
Typically the function subexpression is simply a function identifier. Pure expressions are often referred to as being referentially transparent.
Evaluation of a given pure expression will yield the same result regardless of when or how many times evaluation occurs during program execution. This property is what makes it meaningful to talk about an expression's "value". It also makes it possible to replace an expression with the corresponding value (or it with an equivalent alternative expression) without changing the meaning of a program.
I/O in pure functions
A function can perform input or output and still be pure if
- the sequence of operations on the relevant I/O devices is modeled explicitly as both an argument and a result, and
- I/O operations are taken to fail when the input sequence does not describe the operations actually taken since the program began execution.
The second point ensures that the only sequence usable as an argument must change with each I/O action; the first allows different calls to an I/O-performing function to return different results on account of the sequence arguments having changed.[1][2]
Impure functions in pure expressions
The definitions above still allow some laxity with regard to purity. It is possible for a pure expression to yield an impure function (or more generally a value which contains one or more impure functions).
It is also possible for an expression to be pure even if one or more of the argument subexpressions yields an impure function (or a value which contains one or more impure functions). In this case the impure function(s) in the argument must not be applied during evaluation (but may be incorporated in the result somehow). However, dealing with programs that allow impure and pure functions to be mixed like this can be quite difficult in practice, thus purely functional programming languages do not allow impure functions to be defined. Effect systems, among other things, allow one to reason precisely and formally about the purity of certain expressions even in the presence of higher-order functions etc.; they even allow to prove that a certain function does not have any side effects although it uses impure operations (for example, uses a mutable array for computation internally, but does not expose it to the outer world or maintain its state between invocations).
See also
- Compile time function execution: the evaluation of pure functions at compile time
- Purely functional
- Referential transparency (computer science)
- Lambda calculus
- Side effect (computer science)
- Pure procedure
- Idempotence
- pure keyword in Fortran annotating pure functions
- constexpr keyword in C++ annotating pure functions usable at compile-time