DEV Community

loading...

Functional C++

christianparpart profile image Christian Parpart ・3 min read

Functional Programming in C++

When I learned about C++, around 28 years ago, it's been just labeled as an object oriented programming language, or C with classes and a stronger type system than C.

Now, with the rise of functional programming outside universities since quite some years, the hype has also landed in C++, starting at C++11 and the introduction of lambdas.

One may very well code purely procedural in C++, or purely object oriented. It's just a matter of style. C++ is a very complex programming language, sadly, but that doesn't mean you have to use it all, just because your tool provides this - a common beginners mistake.

However, there are some advantages in using a functional programming style, and what I like most about, are algebraic data types (ADT), that are most sexy declared in first-class functional programming languages (such as F# and alike), but also possible in C++ (one may want to read a future post on this subject right here).

So what's so bad about the imperative style?

for (int i = 0; i < array.size(); i++)
    doSomething(array[i]);

Having a look at this example, the first thing one may note is the index variable being of type int. However, the comparison operator < on its right side has an operand of type size_t (unsigned, most importantly). You can't always compare this, and nowadays some compilers warn (some not), which can render into a bug. Not to mention, that sometimes the loop body may become bigger, and then it's not entirely clear that the index variable i is only and really only modified in the loop header, which isn't guaranteed because it is a mutable variable.
Also, i is only used for referencing the elemeent, nothing else, so we would ideally not reserve another variable just for this - can we avoid that?

So in functional programming style, you'd write that as:

// using namespace std;
// using std::placeholders::_1;

for_each(begin(array), end(array), bind(&doSomething, _1));

This limits the class of errors and uncertainties I mentioned above.

So how would one now sum up an array or list of elements?

auto constexpr numbers = array{1, 2, 3, 4, 5};
auto const y = accumulate(begin(numbers), end(numbers), 0,
                          [](auto a, auto b) { return a + b; });
cout << "sum of elements: " << y << endl; 

The function accumulate is from the numeric header, check out cppreference.org.

So what is so good about it?

It not potentially reduces the lines of code by reusing existing STL functions (such as std::accumulate or std::for_each) but also eliminates mutability, which greatly helps code maintenance due to lesser questions to care about when reading foreign code, but also helps the compiler generating more efficient code.

By using algorithms that have been implemented by others, and used by many, such as the C++ standard library, the chances that those code parts are buggier is also lesser likely than doing it all by your own.

This way of thinking, even in C++, helps you writing more clean code.

Conclusion

In the end, it's always a personal matter of taste. Do you like imperative, procedural, object oriented, or functional programming paradigms? It's at least good to know, that with modern C++ (my code snippets require C++17 above) you have the choice.

A Sneak Peak

I'd also like to talk about algebraic data types in C++17, all the good parts that make C++17 fantastic, and all the amazing improvements about to come in C++20.

Discussion (0)

pic
Editor guide