Pure function
In computer programming, a pure function is a function that has the following properties:[1][2]
- the function return values are identical for identical arguments (no variation with local static variables, non-local variables, mutable reference arguments or input streams), and
- the function has no side effects (no mutation of local static variables, non-local variables, mutable reference arguments or input/output streams).
Thus a pure function is a computational analogue of a mathematical function. Some authors, particularly from the imperative language community, use the term "pure" for all functions that just have the above property 2[3][4] (discussed below).
Examples
Pure functions
The following examples of C++ functions are pure:
floor
, returning the floor of a number;max
, returning the maximum of two values.- the function f, defined as
The value of
void f() { static std::atomic<unsigned int> x = 0; ++x; }
x
can be only observed inside other invocations off()
, and asf()
does not communicate the value ofx
to its environment, it is indistinguishable from functionvoid f() {}
that does nothing. Note thatx
isstd::atomic
so that modifications from multiple threads executingf()
concurrently do not result in a data race, which has undefined behavior in C and C++.
Impure functions
The following C++ functions are impure as they lack the above property 1:
- because of return value variation with a static variable
int f() { static int x = 0; ++x; return x; }
- because of return value variation with a non-local variable
For the same reason, e.g. the C++ library function
int f() { return x; }
sin()
is not pure, since its result depends on the IEEE rounding mode which can be changed at runtime. - because of return value variation with a mutable reference argument
int f(int* x) { return *x; }
- because of return value variation with an input stream
int f() { int x = 0; std::cin >> x; return x; }
The following C++ functions are impure as they lack the above property 2:
- because of mutation of a local static variable
void f() { static int x = 0; ++x; }
- because of mutation of a non-local variable
void f() { ++x; }
- because of mutation of a mutable reference argument
void f(int* x) { ++*x; }
- because of mutation of an output stream
void f() { std::cout << "Hello, world!" << std::endl; }
The following C++ functions are impure as they lack both the above properties 1 and 2:
- because of return value variation with a local static variable and mutation of a local static variable
int f() { static int x = 0; ++x; return x; }
- because of return value variation with an input stream and mutation of an input stream
int f() { int x = 0; std::cin >> x; return x; }
I/O in pure functions
I/O is inherently impure: input operations undermine referential transparency, and output operations create side effects. Nevertheless, there is a sense in which 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.[clarification needed]
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.[5][6]
The I/O monad is a programming idiom typically used to perform I/O in pure functional languages.
Compiler optimizations
Functions that have just the above property 2 allow for compiler optimization techniques such as common subexpression elimination and loop optimization similar to arithmetic operators.[3] A C++ example is the length
method, returning the size of a string, which depends on the memory contents where the string points to, therefore lacking the above property 1. Nevertheless, in a single-threaded environment, the following C++ code
std::string s = "Hello, world!";
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int l = 0;
for (int i = 0; i < 10; ++i) {
l += s.length() + a[i];
}
can be optimized such that the value of s.length()
is computed only once, before the loop.
Some programming languages allow for declaring a pure property to a function:
- In Fortran and D, the
pure
keyword can be used to declare a function to be just side-effect free (i.e. have just the above property 2).[7] The compiler may be able to deduce property 1 on top of the declaration.[8] - In the GCC, the
pure
attribute specifies property 2, while theconst
attribute specifies a truly pure function with both properties.[9] - Languages offering compile-time function execution may require functions to be pure, sometimes with the addition of some other constraints. Examples include
constexpr
of C++ (both properties).[10]
Unit testing
Since pure functions have identical return values for identical arguments, they are well suited to unit testing.
See also
- Compile-time function execution: the evaluation of pure functions at compile time
- Deterministic algorithm
- Purely functional data structure
- 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
References
- ^ Bartosz Milewski (2013). "Basics of Haskell". School of Haskell. FP Complete. Archived from the original on 2016-10-27. Retrieved 2018-07-13.
Here are the fundamental properties of a pure function: 1. A function returns exactly the same result every time it's called with the same set of arguments. In other words a function has no state, nor can it access any external state. Every time you call it, it behaves like a newborn baby with blank memory and no knowledge of the external world. 2. A function has no side effects. Calling a function once is the same as calling it twice and discarding the result of the first call.
- ^ Brian Lonsdorf (2015). "Professor Frisby's Mostly Adequate Guide to Functional Programming". GitHub. Retrieved 2020-03-20.
A pure function is a function that, given the same input, will always return the same output and does not have any observable side effect.
- ^ a b "GCC 8.1 Manual". GCC, the GNU Compiler Collection. Free Software Foundation, Inc. 2018. Retrieved 2018-06-28.
- ^ Fortran 95 language features#Pure Procedures
- ^ Peyton Jones, Simon L. (2003). Haskell 98 Language and Libraries: The Revised Report (PDF). Cambridge, United Kingdom: Cambridge University Press. p. 95. ISBN 0-521 826144. Retrieved 17 July 2014.
- ^ Hanus, Michael. "Curry: An Integrated Functional Logic Language" (PDF). www-ps.informatik.uni-kiel.de. Institut für Informatik, Christian-Albrechts-Universität zu Kiel. p. 33. Archived from the original (PDF) on 25 July 2014. Retrieved 17 July 2014.
- ^ Pure attribute in Fortran
- ^ Pure attribute in D language
- ^ "Common Function Attributes". Using the GNU Compiler Collection (GCC. Retrieved 22 July 2021.
- ^ constexpr attribute in C++