Monads are part of C++, and are in your code

For several reasons, I didn’t get a CppCon ticket this year, but since I live in the Denver metro area I did go on the Friday, which is free to attend. Herb’s closing keynote (Cpp2) was thought provoking. At one point though, he said,

Think about the words and the ideas that we have been using for the last hour and a half. I have not said the word ‘monad’ once!

Herb Sutter, Simplifying C++#9 of N, CppCon 2022

The general audience reaction: laughter.
My reaction: inward sigh.

Herb was trying to make the point, throughout the talk, that he’s sticking with C++. That he’s for evolution, not revolution. That C++, if we can make it simpler, safer and more toolable, is right for the future. And that’s great. It was unfortunate that he picked on monads though, because it came off to my ears as a cheap shot, and because I think it doesn’t make his point, or at least is very likely to be misconstrued.

Because monads are part of C++.

They’re not some alien thing. They’re just as much a part of C++ as RAII; templates; any pattern you care to name; even functions and classes. When I write some code, often I don’t think about writing a particular pattern. But knowing about patterns helps me realise what I’ve done when I step back and take a look. It can be the same story with monads. They’re in the code, waiting to be recognised and to help us understand what we’ve done.

Monads are part of C++, because monads are part of programming.

We have many tools in the C++ toolkit. C++ is famously large; it contains multitudes. By design. In fact, we can take a cue from Herb’s talk and ask, “What would Bjarne say?” Well, he already said it, several times, in The Design and Evolution of C++:

People don’t just write classes that fit a narrowly defined abstract data type or object-oriented style; they also — often for perfectly good reasons — write classes that take on aspects of both. They also write programs in which different parts use different styles to match needs and taste.

The language should support a range of reasonable design and programming styles rather than try to force people into adopting a single notion.

There is always a design choice but in most languages the language designer has made the choice for you. For C++ I did not: the choice is yours. This flexibility is naturally distasteful to people who believe that there is exactly one right way of doing things. It can also scare beginners and teachers who feel that a good language is one that you can completely understand in a week. C++ is not such a language. It was designed to provide a toolset for professionals, and complaining that there are too many features is like the “layman” looking into an upholsterer’s tool chest and exclaiming that there couldn’t possibly be a need for all those little hammers.

Bjarne Stroustrup, The Design and Evolution of C++

Bjarne was very deliberate in designing C++ for working programmers, and it’s clear that making C++ 10x more teachable and learnable — to paraphrase something Herb brought up — is not a goal for C++, at least not when it conflicts with features and choice. Many techniques and tools are available to the C++ programmer, and monads are certainly one of them.

Herb knows this, of course. His throwaway line was just that: a bit of clickbait. But there is a better message here about monads. Let’s not make them a strawman scapegoat for things that we think are weird and don’t belong in C++, because that’s not really a tenable position.

The more nuanced, more important message to convey about monads and other functional patterns is this: write clear APIs that fit the domain.

When we write classes, functions, variables, templates, APIs, we don’t tend to give them — unless the point is to be very generic — generic names. We give them names that fit their domain. So-called functional patterns are currently suffering from abstract names because they are new and they come with these abstract names, and because we programmers — and I include myself very much in this — are neophiles and pedants. There is hope that this is slowly changing, and that as we gain experience with these patterns they are becoming a more normal tool; not particularly more special than any other, but nonetheless very useful. The important thing is not the hammer, but what we build with it.

I’ve given talks where I described techniques that any functional programmer would immediately recognise as applications of monads or monoids. I was completely aware of this; nevertheless I tried to keep the talks focused on familiar domains so as to be accessible and grounded in examples. Understanding of abstraction comes after seeing concrete instances, not the other way around.

David Sankel has also given talks covering this theme: if you’re writing an API for some domain, use that domain’s language. Don’t use “bind” or “fmap” as function names if you have terms that fit your use better.

P2300 is a major proposal presenting a model for asynchronous execution in C++. The word monad does not appear in that paper. This is definitely not because the authors don’t know what monads are! I am quite sure that every author of that paper is well-practised with monads as a general tool and the continuation monad in particular, and as such the design they came up with was very deliberately monadically-informed. And this is incredibly useful, because it means we can have confidence about the power of the P2300 design. We can lean on what we know about the expressive and compositional capabilities of monads.

A proper question to ask in a critique of any programming interface, that Herb was implicitly and explicitly asking throughout his talk, but which the monad jab jarred with, is not “can we do X?” but “is doing X ergonomic, safe, explainable?” As programmers we get so caught up in asking binary questions that we frequently get the wrong idea that everything should be so categorised. But that line of questions just leads to uninteresting answers and lack of communication. More often than “is it Turing complete?” perhaps we should ask, “is it Pac-man complete?”

Monads are part of C++. They’re also part of Cpp2, even if Herb didn’t say the word. And just like other patterns, if you develop a sense for them, they become part of your toolkit. And they are a very useful tool. But we don’t name the things we build after the tools we use. And choosing not to say “monad” in a talk is a pedagogical device and a recognition of familiar C++ vocabulary — not an implication that monads are weird and other. That is not helpful, and not the C++ way.

Categorized as C++