Functional Programming in C++, from a Scala Perspective 1/7

In 2025, at the season opening of Italian C++ Community meetups, I presented the talk, “Beyond Assertions,”. That was my very first talk in front of a frighteningly vast public (some 70 people) full of strangers.

I was more than a bit scared, and it wasn’t so easy to keep my anxiety at workable levels, but eventually it went all right. I had good feedback both from the audience and from the community team. And that encouraged me to try this experience again. Don’t they say that adrenaline gives you addiction? But what could I tell a crowd of skilled C++ programmers that they didn’t know already?

“Beyond Assertions” focused on using strong typing to move correctness checking from runtime to compile time. That was a topic I felt the urge to announce to the world: software correctness is never enough, and I was under the impression that traditional programmers could benefit from stronger typing. The talk came out after a few posts (Assert? Yes, but actually No, https://www.embeddedrelated.com/showarticle/1651.php, As Smart as a Smart Type – Theory and As Smart as a Smart Type – Practice (C++)) I wrote on the subject.

So I dug into my experience looking for something worth telling fellow programmers. I manage to be somewhat C++20ish (the more recent standard I used at work), but I am not really up to speed on what came later with C++23 and 26. Nor can I present fancy techniques, for I use plain C in my everyday job. Indeed, I am trying to become a better functional programmer. I use Scala for the Advent of Code (2023, 2024, 2025), and I really like the language. I even tried to translate the Scala functional approach to C++ with mixed results (I enjoyed it and found it very expressive; my manager much less so)…

That triggered the idea: I could present Scala to C++ programmers, hiding this presentation in describing how C++ copes with a functional programming approach while comparing it with a “real” functional programming language.

Around that kernel, I developed the idea – what is worth that hard-battled C++ programmer knows about functional programming? Would I be able to talk about Scala while telling a C++ audience why they should be interested in functional programming?

I presented the idea to the community manager, the ever-positive and encouraging Marco Arena, and he enthusiastically approved.

Challenge accepted. To prepare, I wrote a long text about what I planned to present before sketching the slides. Now that the presentation is over, I think my preparation is worth sharing with a bit of editing. Like … you saw the movie, now you can read the book. Given the length, I had to chop it up in parts, so this is more like a series than a movie. As expected, the book has more content than the video.

I hope you’ll enjoy.

The Basics

What is FP?

FP is programming with functions.

C++ programmers know what functions are: things that are called that may or may not have parameters and that may or may not produce a result.

But FP is not about that kind of functions. FP functions are the mathematical concepts we studied back in high school, the stuff like y=f(x) with those nice graphs.

I can hear you say – I did that in high school, and I remember how boring and frustrating they were; I don’t want those in my code. Bear with me for a few posts, and I’ll show that this way of programming is worth knowing.

Everyone knows Alan Turing. He was the talented scientist who invented, almost a century ago, a great deal of computer theory. A compendium of mathematical theorems that prove what can be computed and what cannot. To this purpose, Turing developed the machine christened after his name.

What is much less known is that Turing studied under Alonzo Church at Princeton University. Church was an outstanding mathematician and contributed to the theory of computability as much as Turing did. While Turing devised a mathematical model of an abstract computation machine, Church identified a class of mathematical functions and rules for implementing computable algorithms.

He formalized his work under the name lambda calculus. Church and Turing proved that lambda calculus and the Turing machine could solve the same class of problems. In other words, they are equivalent.

Church was also very eccentric. There are several anecdotes about him, from his obsession with clean blackboards before starting a lesson to the enigmatic answers (yes, more than one) to the question of why he chose the Greek letter lambda (my favourite – “eeny, meeny, miny, moe”).

In 1958, John McCarthy, an MIT researcher, was working on a new programming language named LISP (note the year; COBOL was not invented yet, only Fortran existed as a high-level programming language). Incidentally, he came across Church’s paper on Lambda Calculus, and John decided to implement it in LISP.

Enough with history. I won’t return to lambda calculus. In the same way no one writes programs for the Turing machine, no one writes programs in lambda calculus. At least, not for serious purposes. If you are curious about what lambda calculus looks like, I wrote a couple of posts about it. The first was a detailed and commented report about a talk at the Lambda World 2017 conference Lambda Core, Hard Core, by Jarek Ratajski. The other one was a solution to a programming riddle: Lambda Headache for Mere Mortals.

So, let’s take a closer look: what is functional programming? It is programming by composing and applying functions. Functions are defined as their mathematical version, as a way to map the function argument to a result.

In this sense, the function does not describe an imperative execution that mutates the state to compute a value, but the composition of expressions.

Back when the world was young, and computers were only for nerds and nerds were wildly unpopular, I remember I was trying to understand programming languages. There was something in the statement LET x=x+1 of the (Sinclair) BASIC that escaped me. So I brought the line to my math teacher, and she had no clue as well.

If you stand clear of what you know and consider that line an equation, you see that it simplifies to 0=1, which is false. The reason is that the line is not mathematics – it is an imperative command to modify a state of the execution. This is fairly remote from mathematics, where if you say x=3, x is bound to have that value; you cannot change it later to something else.

Interestingly, functions are composable – meaning that if you have sum and multiplication, you can define the vector product, which is a new function. This is a very interesting property for us programmers – the problem of modularization and reuse is solved by composing modules, usually with great pain. A language that promises to be composable from its very basic building blocks is going to, at least, reduce the pain.

Trying to sum up and condense the principles behind functional programming, we can say:

RULE 1 – Variables cannot be changed after their first assignment (consider them constants).

RULE 2 – A function’s result is determined only by argument values; in other words, functions are deterministic.

RULE 3 – Functions are first-class citizens – they can be assigned to a variable, passed as an argument, returned as a result, and you can perform operations on them (such as composition).

C++ and Scala

The C++ language, in the words of its own creator, is promoted as a multi-paradigm language. The idea is that by using C++ you are not bound to a specific paradigm (such as imperative programming), but you can choose the paradigm that better suits your needs.

For sure, C++ started as a C language spin-off, with clear imperative roots. Object-oriented was the hype of the 90s – everything had to be object-oriented (even COBOL got object-oriented features in its standard review). Generic/Meta programming is another paradigm that C++ sort of stumbled upon, but it’s now well supported. There is another paradigm, called Logic Programming, a restricted realm where the Prolog language is the main player (this gained some popularity in the 90s when Japan announced that Prolog would power their AI research). This is not the time to go down this rabbit hole, but trust me, C++ has no feature to write any logic programming1.

What about Functional Programming? That’s what we are going to see in the series of posts. And I’ll use another language I know a bit to better understand what kind of support a functional programmer expects from a functional language. This touchstone will be the Scala programming language.

Scala was designed by Martin Odersky and made public in 2004 as a multi-paradigm programming language that runs on the Java Virtual Machine. Scala offers several tools for functional programmers and can easily interface with Java code and its ecosystem.

Scala has evolved over the years; the current version is 3, and it has been used in distributed systems (and still is). Notably, companies like Twitter and LinkedIn pioneered it at scale, and many famous firms still use it, including Zalando, Morgan Stanley, Airbnb, and others. One of the main criticisms of Scala is the steep learning curve, but… hey, we are C++ programmers; we are used to climbing steep curves… every three years now.

That’s enough for this post. We’ve seen what and why. Next time we start putting these three rules to the test in actual C++ and Scala code — starting with the one that sounds simplest and turns out not to be: variables that can’t change.

  1. This is not entirely true – template meta-programming has many similarities with logic programming. As put by an LLM:
    Template partial specialization acts as the base case or the ground truth—the facts—while the primary templates act as the recursive logic or rules that define how to derive a result.
    When the compiler encounters a type, it essentially performs a search for the most specific match. If a partial specialization exists that fits the criteria, the compiler “unifies” the current type with that specialization, much like Prolog matches a goal against a fact in its database. If no specific fact matches, the compiler falls back to the general rule (the primary template).
    This mapping is especially evident when implementing recursive structures, such as a compile-time list or a type-level search. The Rule (Primary Template): Defines the general recursive step (e.g., “To process a list, process the head and then recurse on the tail”). The Fact (Partial Specialization): Defines the termination condition (e.g., “An empty list is processed as an empty result”).
    By treating types as terms and specializations as clauses, you are essentially using the C++ compiler as a logic engine to execute a program at compile time.

    ↩︎

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.