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).
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
void f() { static std::atomic<unsigned int> x = 0; ++x; }
The value ofx
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
int f() { return x; }
For the same reason, e.g. the C++ library functionsin()
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 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.[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.[7] 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).[8] The compiler may be able to deduce property 1 on top of the declaration.[9] - In the GCC, the
pure
attribute specifies property 2, while theconst
attribute specifies a truly pure function with both properties.[10] - 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).[11]
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". FP Complete. https://www.schoolofhaskell.com/school/starting-with-haskell/basics-of-haskell/3-pure-functions-laziness-io. "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". https://github.com/MostlyAdequate/mostly-adequate-guide/blob/master/ch03.md. "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."
- ↑ "Common Function Attributes - Using the GNU Compiler Collection (GCC)". Free Software Foundation, Inc.. https://gcc.gnu.org/onlinedocs/gcc-6.1.0/gcc/Common-Function-Attributes.html#index-functions-that-have-no-side-effects-3202.
- ↑ Fortran 95 language features#Pure Procedures
- ↑ Peyton Jones, Simon L. (2003). Haskell 98 Language and Libraries: The Revised Report. Cambridge, United Kingdom: Cambridge University Press. p. 95. ISBN 0-521 826144. http://it.bmc.uu.se/andlov/dev/books/haskell98-report.pdf. Retrieved 17 July 2014.
- ↑ Hanus, Michael. "Curry: An Integrated Functional Logic Language". Institut für Informatik, Christian-Albrechts-Universität zu Kiel. p. 33. http://www.informatik.uni-kiel.de/~curry/papers/report.pdf. Retrieved 17 July 2014.
- ↑ "Common Function Attributes - Using the GNU Compiler Collection (GCC)". Free Software Foundation, Inc.. https://gcc.gnu.org/onlinedocs/gcc-6.1.0/gcc/Common-Function-Attributes.html#index-functions-that-have-no-side-effects-3246.
- ↑ Pure attribute in Fortran
- ↑ Pure attribute in D language
- ↑ "Common Function Attributes". https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html.
- ↑ constexpr attribute in C++
Original source: https://en.wikipedia.org/wiki/Pure function.
Read more |