Functional Programming
![]() | |
Haskell logo |
The main concept which is adressed by the functional programming paradigm is the evaluation of mathematical functions instead of changes within states of the executed commands (imperative and object-oriented paradigm). In the context of functional programming, a function can be used as an argument for a function as well as a function can return another function (higher order function concept). Associated with the avoidance of states, this paradigm is known for its absence or reduction of side-effects.
A function is said to produce a side effect if it modifies some state other than its return value. This behaviour complicates the prediction and evaluation of a program, for example the following statements (++i) - (++i) do not only calculate a value, they also change the state/value of the variable i. Therefore pure functional programming disallows side effects completely. Since pure functions do not modify state, no data may be changed by parallel function calls. Pure functions are therefore thread-safe.
In C++ there are several ways to use this paradigm:
![]() | Template functions
|
![]() | Function objects
|
![]() | (Template) meta-programming |
The first two techniques are compared in the next two code snippets. The third technique is explained in the next section. The main reason why two different techniques are used in C++ is based on the fact, that declaring a function to be inline is not going to help, because compilers do not inline calls to functions passed to templates through a pointer.
A standard container is used together with a simple sort algorithm. The next code snippet presents the example with the function, where compilers will instantiate std::sort with the following argument types: double, double, bool (*)(double, double) and then call it, passing it a pointer to less_abs_fun. The requirement for the container is that the begin and end is available as well as the positions of the container can be accessed arbitrarily (random access concept). Every two elements are compared with the mechanism of the passed function and depending on the result, the positions are swapped.
bool less_abs_fun(double x, double y) { return std::abs(x) < std::abs(y); } int main() { std::vector<double> container; std::sort(container.begin(), container.end(), less_abs_fun); }
Compared to the simple function, a technique called function objects is used. On the one side, passing a function object to the generic algorithm opens up the possibility for the compiler to inline the algorithm. On the other side, a function object can be initialized with an additional state.
It has to be noted, that parentheses after the name of less_abs are required to construct an unnamed or anonymous object of the class. The object contains no data, and we pass it to the function only for its type.
struct less_abs { bool operator()(double x, double y) const { return std::abs(x) < std::abs(y); } }; int main() { std::vector<double> container; std::sort(container.begin(), container.end(), less_abs()); }
As can be seen the C++ implementation uses a hard-coded numeric value which means that several algorithms has to be implemented. Functional programming languages such as Haskell and ML use only the required concepts for their functions. This drawback is released due to the generic programming paradigm which is explained in the next section.
From our point of view, the full power of the functional paradigm can be revealed if functional programming is used in combination with the object-oriented and the generic programming paradigm. The C++ STL is an example of this multi-paradigmatic programming style.

