Immutable Data

A key to pure functional languages is that their data are immutable. Therefore, assignments such as x= x+1 or ++x are not possible in the pure functional language Haskell. The consequence is that Haskell supports no loops like for,while, or until. They are based on the modification of a loop variable. Haskell does not modify existing data; Haskell creates new data when needed and reuses the old ones.

Immutable data

Immutable data has a nice property. They are implicit thread-save because they miss a necessary condition for a data race. A data race is a state, in which at least two threads access a shared data at the same time, and at least one of the threads is a writer.

Quicksort in Haskell

The quicksort algorithm in Haskell shows very nice the immutability of data.

The quicksort algorithm qsort consist of two function definitions. In the first line, the quicksort will be applied on the empty list. Of course, the result is an empty list. In the second line, there is the general case in which the list consists of at least one element: x:xs. x is the first element in the list and xs the reminder by convention.

The strategy of the quicksort algorithm can be directly applied in Haskell.

Use the first element of the list x, the so-called pivot element and make a list with one element out of it: ... [x] ...

No worries. I will not try to explain the algorithm. A simple observation is enough for me. The elements are overwritten in line 9 - 11. The algorithm works in-place and needs, therefore, mutable data. There exist a nice term in the functional programming for this overwriting: destructiveassignment.

To be honest that was an implementation of the quicksort algorithm in C. With C++ we can do better if I use the std::partition.

But once more. The key point is that I use also destructive assignment in std::partition. If you look very carefully, the strategy of the C++ version is not so different from the Haskell version.

What is the story about immutability in C++?

Immutable data in C++

The usage of immutable data in C++ is based on the discipline of the programmer. You have with constant data, template metaprogramming, and constant expressions three ways to express the immutability. The options one and two are quite easy to present but constant expressions deserve more attention.

Constant data

By using the instruction const int value= 1;value becomes an immutable data.

Template metaprogramming

Template metaprogramming takes place at compile time. At compile time there is no mutation. Therefore all values that are calculated at compile time are immutable. Of course, that holds true for the calculation of Factorial::5 at compile time.

If the short notice to template programming was too short for you, please read the post Functional in C++98.

But now back into the future of C++: constant expressions.

Constant expressions

C++11 supports constant expressions. With C++14 you can declare functions as constant expressions that behave almost as usual functions.

C++ supports constant expressions in three variations: variables, user-defined types, and functions. The special about constant expressions is that they can be evaluated at compile time.

By using constexpr double pi= 3.14pi becomes a constant expression. pi is, therefore, implicit const and has to be initialized by a constant expression: 3.14.

There a few restrictions for a user-defined type so that the instances of the user-defined type become constant expressions. For example, the constructor has to be empty and a constant expression. The instance can only use methods that are constant expressions. Of course, you can not invoke a virtual method at compile time. If a user-defined type fulfils all requirements, you can instantiate and use its objects at compile time.

To execute functions in C++14 at compile time, the have to follow a few rules. Firstly, their arguments have to be constant expressions. Secondly, they can not use static or thread-local data.

The following example shows what power lies in constant expressions. I use user-defined literals to calculate all distances at compile time.

I will not repeat myself by explaining constant expressions and user-defined literals in detail. I have already done it in the posts to constexpr and user-defined literals. I want to make only two observations:

By the declaration constexpr all variables, instances of the class MyDistance and functions become constant expressions. The compiler performs, therefore, the necessary operations at compile time.

All variables, instances, and functions - excluding std::cout - are constant expressions. That means the entire program will be executed at compile time. Therefore, all used variables and instances are immutable. Only the output of the program 255900 m in line 77 is performed at run time.

What's next?

Pure functions are quite similar to mathematical functions. They are the reason why Haskell and template metaprogramming are called pure functional languages. But what are the restrictions that a pure functional language has to fight with? These will be my topic of the next post.