Is C++ moving too fast?

I recently attended a C++ meetup in London, where Vittorio Romeo gave a very interesting talk on his proposal for the addition of Epochs to the C++ standard. In short, Epochs are a mechanism for evolving the C++ language (inspired by Rust’s Editions) by allowing different Modules to comply with different language versions. It is an eminently sensible idea, that seems like a neat solution to a real problem, though it does throw up some thorny implementation issues.

The long road to standardisation

This post is not about Epochs. It’s about my concerns with the thought processes that lead up to the committee considering these kinds of changes. Firstly, a little background. I started learning C++ in around 1992. It has been my main programming language (with a few periods of subservience to Python, C#, and Javascript) for going on 30 years. And for the first 20 years, nothing changed. Well, that’s not quite true – the STL matured, standardisation got better, ATL, boost, and others extended the language with useful general-purpose APIs – but the core language was pretty static. And it is a massive credit to the C++ committee and community that, after all that time, it was recognised that things had to change. And change did come – move semantics, lambdas, useable smart pointers. All fantastic stuff that has been lapped up and adopted to a very wide degree.

But now we start to get to the crux of the matter. These were changes that were inspired by other languages that had been around, developing these concepts for almost as long as C++ had existed. They were design choices and implementation decisions based on years and years of real usage. And their integration into both the various codebases and the mental models of programmers around the world was manageable. We had a wealth of understanding of what problems were hard to solve with the existing toolkits available in C++ and of the pitfalls of using and abusing what was there.

It’s all about the rate of change

But now after 20 years of no change at all, the last 10 years have seen the C++ landscape morph into something almost unrecognisable. Concepts and Modules, Spaceship Operators and Ranges, all fantastic ideas and based on real-world problems, but being introduced at a rate that can leave a programmer’s head spinning. We do not have 20 years of people working with Modules, trying to understand how to use them efficiently and intuitively in their APIs. We do not even have a body of programmers who have internalised these things and who can translate a problem domain into appropriate language constructs without looking up the docs every 5 minutes. So how can we sensibly and intelligently debate the usefulness of a feature that is built on top of Modules? And how can we even begin to guess at the impact of introducing such a feature to an existing codebase?

And there are several compounding factors that are feeding into this problem. Firstly, people are rightly drawing inspiration from other languages. But the languages they are drawing from are increasingly languages such as Rust and Go; relatively new languages that have not themselves shaken out all their own issues. It is good to look outside your scope for inspiration – necessary even – but when you take the new shiny things from a new shiny language, you only get a new idea, not the truly valuable insight of being able to observe the large scale effects of a community living with that idea for many years.

Who are we making these changes for?

Secondly, there is the problem of self-selection bias. Self-selection bias is a problem that we are well aware of in the games community. Say you come out with an idea for a game, you get it to a certain point, you release it on early access and you get a bunch of early-adopters on board. So far so good. But as you introduce features you start to get feedback from those early-adopters and this brings with it a bunch of trouble. Maybe your control system is too complicated, and to gain a wider audience, you need to drastically simplify it. Understanding and dealing with this issue is now hampered by the fact that your userbase is made up of people for whom a complex control system was not an insurmountable barrier. In fact, your user base may well skew towards people who enjoy the challenge of a complex control system! And now you are left trying to solicit useful feedback from a group who may oppose the very changes you need to make to reach a wider community.

This brings me to the committee themselves. It is natural and unavoidable that the committee is made up of people who understand and are interested in the language of C++. These are not your average C++ programmers. Your average programmer wants the language to get out of the way of them implementing a feature or fixing a regression. They do not care about the language itself, only about whether it will help them to achieve their goal of creating functioning software. This is a very hard thing for the committee to keep sight of as they will naturally self-select for atypical programmers who see the language itself as an interesting thing and not just a means to an end. This is not a criticism of the committee and is not a problem unique to C++ (self-selection bias affects everything from national politics to local community groups), but is something to bear in mind when considering the pace of change in the language.

We need time to talk

So really this brings everything back to my personal mantra – “there is only one hard problem in software engineering: communication between software engineers”. Ideas such as Epochs are perfectly good, but how are you going to effectively update the mental models of millions of programmers, programmers who do not care about Epochs for their own sake? How are you going to get them to use them effectively? How are you going to learn from their experiences of using them? How are you going to learn from their experiences of using Modules when no one has even started using Modules yet?

All of this process was implicit in the release of C++11 – everything had been static for so long that people were hungry for new solutions to old problems, and information on the shortfalls of the current world order was plentiful and readily available. Even the massively extended release cycle – while frustrating to many – allowed those ideas a lot of time to bed in and harden, both in codebases and minds world-wide. But with every release since then this has become less and less true, and now as we are planning C++23 and C++26 I fear we are rushing ahead too fast and may well end up tripping up over mistakes we haven’t yet realised have been made.