C++ is at a challenging point of time. In part one we discussed “The Tragedy of C++”, as presented by Sean Parent in Cpp North 2022. Today, we will discuss the alternatives for C++, what they are aiming to solve and some thoughts on the future of C++ with its alternatives in mind.
Be Safer with Rust
We already compared Rust and C++ in a previous blog post. Rust is unique in a way, having manual memory management with compile-time safety. The Rust model not only helps prevent memory segmentation faults or leaks, it makes concurrency easier, as data races – trying to access the same memory from different threads without proper locking – are checked at compile-time.
Rust is a good language with significant advantages and a big community of fans. It is not experimental! And yet it didn’t gain the popularity one would expect it to gain, having the efficiency of C++ without the risky parts.
The reason for the slow adoption of Rust in the industry, compared to the vast usage of C++, may be first attributed to the significant head start C++ has over Rust, with about 30 years of legacy code. C++ also relies on the C syntax, which despite all of its pitfalls is still commonly known. But if it is only the head start of C++, and Rust is objectively better (even defining “better” is a matter of debate; over the years the industry should realize which language is most efficient for each domain) – we would eventually see a more massive migration to Rust.
Many C++ developers argue today that memory management safety is not their biggest problem in C++ with proper use of smart pointers. David Sankel listed in C++ Now 2022 the Rust features he would like to see in C++, focusing on smart enums with pattern matching, reflection and injection metaprogramming, good tooling, and ergonomics (safer memory management is not in his top list of required features, as it is already well mitigated in C++). The problem is that it is not easy to port these desired features into C++ – partly because of the complexity of C++ and partly because of the C++ evolution process which makes it hard to bring new paradigms into the language (maybe with a good reason). It’s an uphill battle, as David Sankel says.
Towards the end of the talk, David asks: “Is C++ under threat to become a legacy language?” – don’t expect an answer, it is an open discussion.
The bottom line is that Rust is a real competition to C++, with attractive features and real life projects. It also appears to be gaining momentum. If nothing interferes (Carbon?) it may continue to gain popularity.
Running Ahead with Circle Compiler
While C++ evolution is tied to the ISO committee process, forking C++ is an option. The most known fork out there is Circle – a new C++ compiler that extends C++ by adding many novel language features, some of them are based on proposals that did not pass the committee or are still in the channels.
Circle proposes many interesting features, such as:
- Pack subscripts with pythonic-like syntax
- Reflection and Introspection
- Pattern matching
- Member traits – a much nicer syntax for type traits
Is it production-ready? I don’t know of any real projects that use Circle. But it certainly shows a possible path for C++! Would it become a production-ready compiler driving a new variant of C++? Or maybe another variant of C++ will arise and take the lead? The important point is that Circle presents a potential path of C++ evolution, in the sense that C++ can actually take ideas from Circle and evolve based on those innovations that prove to be useful and productive in Circle. Maybe something that can be seen as a kind of Technical Specification (TS). Maybe in the same manner that C++ adopted Ranges TS and Concepts TS, it can adopt ideas from Circle. Or, perhaps if Circle would gain more popularity it may become a real production environment, which would make it an actual new language competing with C++.
For a good presentation of Circle’s abilities, see the talk by Sean Baxter – the man behind Circle – at C++ Now 2022.
Then Came Carbon
Carbon was announced at CPP North in July 2022 as an experimental successor for C++. The development of Carbon started a few years ago (the first pull request in the current master branch is from about 2.5 years ago, but this branch was created from an older private repo). The language is currently backed by Google, but it is built as an open source.
The motivation for creating Carbon is explained in its GitHub page. The main idea was to build a modern language that can easily interleave with C++ – having bidirectional interoperability with C++. That is you should be able to call existing C++ code from Carbon and vice versa. This is a huge plus for a migration path for any organization that has a big C++ code base and is looking to migrate to a new modern language.
Trying to consider whether Carbon is actually a potential successor to C++ is hard. First, as Carbon itself states, it is still experimental. You can play with it, but it does not advertise itself as ready for production. And then of course comes the question of what are the benefits of Carbon over C++ (or over Rust) that would justify an adoption of a (yet another?) new language. As opposed to Rust, Carbon does not yet include a memory safety model, which would make it harder to have interoperability with C++. And the other nice perks that come with it come with a price of an unfinished feeling, cryptic compilation errors when you play with it and features that you look for and are still on the roadmap.
It is interesting to mention that Google already pushed a language that was supposed to be a successor to C++ – Go. You can find questions about this already, including a reddit post asking (cynically maybe?): “Carbon is designed to replace C++, but I thought golang was?”. But, the industry realized that even though Go has its own virtues (which made it gain its position) it is not a real substitute for C++ when performance really matters. This might explain Google’s desire to come up with a new potential successor for C++, this time closer to the C++ model.
The basic similarity of Carbon syntax to Rust led in a reddit discussion to the idea that the migration path from C++ to Rust may be through Carbon:
C++ → Carbon 0.1 → (safe) Carbon 1.0 → Rust 1.x
Note that the current Carbon version is still 0.1; the Carbon 1.0 mentioned does not yet exist.
My view is that at this point in time, Carbon is more of a threat to Rust than for C++, as projects and companies who were considering exploring Rust might hear of a new language and say “let’s wait to see how this fight evolves”. In the long run it may be good for Rust, as the mere discussion would make people explore alternatives for C++.
Why did D, Nim, and Zig not gain momentum?
There has already been an attempt to come up with a successor to C++. It is called D.
And it’s far from the only one. There are other languages such as Zig, Nim and many others, which try to address the original sins of C syntax while preserving the basic paradigms of a compiled language with manual memory management (or as in D, with a garbage collector but with an option to opt out from using it). They are all doing quite well theoretically (see for example this Hacker News post on working with Nim), but struggling with actual adoption.
What makes a language succeed or fail?
That’s a very complex question. But I think there are a few common key factors for success, and it is not required to have them all:
- Being backed by a strong community and/or by industry leaders – this is lowering, at least conceptually, the risk of adopting a new language.
- Having a big known project as its model, e.g. Mozilla Firefox for Rust.
- Presenting a new paradigm, something that could be considered as a leap in productivity compared to other existing languages.
- Solving an actual problem that is present in other existing languages.
- The basics should be easy to use, and complex parts should have a good reason to exist and should be hidden.
When it comes to arguments for a new language, Carbon refers to Why Not Rust, but ignores D for some reason. As opposed to Carbon, D preserves compatibility with C but less so with C++ and it explains why, and how to mitigate this, which may be an argument in favor of Carbon, or not (it’s a double-edged sword). As for the use of a garbage collector in D, it is true that D allows you to opt out from using the GC, but it may add some complexity to your code (here are two good resources on D’s GC and how to avoid it or opt out, in D’s official blog and in D’s forum).
It is hard to foresee whether a new language would be widely adopted. One big plus for Carbon is that it is backed by Google. I would take a hypothetical bet that if it was not backed by Google (and by known figures from the C++ community) it would not get the attention that it got. Which does not come to decrease its potential success. But it seems that the current hype and buzz around Carbon might be too early.
Other Interesting Compiled Languages to Look At
If you are already exploring new languages such as Carbon, here are a few other interesting languages you could explore:
Val – as mentioned above, Val aims at mutable value semantics for correctness, safety and efficiency with other features influenced by Swift. It’s led by Dave Abrahams and others, and is used mainly for researching language paradigms. See the great language-tour page.
Pony – an actor-model language, with memory management and thread safety in mind. Pony adheres immutable states and isolated data to achieve thread safety and simple code. It hasn’t yet reached version 1.0, API and syntax may change.
Odin – a C-like language with better type safety and many other interesting additions and tools. Data structures are just data, without methods, but subtypes and polymorphism are possible.
Don’t feel obligated to review these languages or any other, but if you are in the process of exploring languages and new paradigms – you should be aware that there are many out there!
What Are We Trying to Solve?
We referred in previous sections to the problems new languages are trying to solve. But a very fundamental question is whether these problems are the actual productivity traps. Fred Brooks, in his famous paper On Essence and Accident in Software Development, divided the difficulties in software development to essence, the difficulties inherent in the nature of software, and accidents, those difficulties that today attend its production but are not inherent. Brooks’ claim was that there is no Silver Bullet that can significantly improve software development productivity, as the major complexity in software development is in the essence while new tools and methodologies are dealing with the accident part. The paper, published in 1987, predicted for the next ten years:
“[…] as we look to the horizon of a decade hence, we see no silver bullet. There is no single development, in either technology or in management technique, that by itself promises even one order-of-magnitude improvement in productivity, in reliability, in simplicity.”
Most software developers would agree that the claim made by Fred Brooks in 1987 for the next decade is still true today, more than 30 years later.
The natural question is then whether the new languages are solving the fundamental issues – the essence of the problem, or just the tip of the iceberg. It’s not an easy question and actually quite subjective. One may even argue that in some cases the urge to create new languages is part of the human nature of trying to leave a stamp and be different, even if the net value is negligent or insignificant.
The Big Paradigm Shift for Changing How We Program
Most popular languages today are still imperative. The programmer needs to think on all the steps for solving each tiny piece of a problem. Yes, we have functions and libraries and techniques that try to be more declarative, but in the end it is not more than a mix-and-match between the high level abstractions and low level tiny implementation details, bits and bytes.
Tony Van Eerd referred to the term “Complecting” in his 2021 C++ Now lightning talk and elaborated on that in his talk at Cpp North 2022. Tony has brilliant advice on how to build your code easier: “Code top-down on the way down and bottom-up on the way back up”, you may have to follow his talk in that link to get the entire idea. Coding top-down is not new, we actually do that most of the time. The problem is when we do not, we mess things up (and then need to meet a master to get some wisdom). But with any good advice that you get, programmers still need to think on the level of details and abstractions of each function and class, not to go into too much detail and on the other hand not to build too many levels of abstractions. We all know the fundamental theorem of software engineering: “We can solve any problem by introducing an extra level of indirection except for the problem of too many levels of indirection” (attributed to David Wheeler).
More than just needing to think about the levels of indirection and abstractions, C++ programmers still need to deal with the question of whether they want to pass by-value, by-reference or maybe by-const-reference (ignoring the pointer and smart-pointer options). This is so technical, and in many cases, in C++, we sacrifice safety and correctness for the sake of presumed efficiency, and in the end actually hurt performance as sharing data is costly for concurrency. Dave Abrahams talked about that in his keynote and his following part 2 talk at C++ Now 2022. He also presented the Val language which is a research programming language trying to explore the ideas of value semantics, correctness and safety by default with built-in efficiency based on copy-on-write. While the Val language does not presume to be a substitute for C++, the ideas that it raises may affect the future of C++ and other languages. The nice idea in Val is that the language tells the programmer: send by-value, we will take care of not copying if there is no need. Such ideas, getting the burden of decision back to the language seems to me the right direction.
The big paradigm shift would take time, maybe a decade or two, maybe more. But eventually there should come the declarative languages that would allow focusing on the problem domain, the “what”, and not the “how” – with a proper machinery for generating the required execution artifacts that satisfies the problem domain. It might be gradual, but we will see more and more parts of the system being described in a more declarative way, shifting away more and more from the imperative style.
Even when we would have these new declarative languages that would actually make our lives easier, we may still have C++ underneath.
The Future is Not Written Yet
Getting back to Sean Parent’s keynote at CPP North, following his keynote, Sean posted his conclusion:
“Act Three is not yet written. Will C++ continue on its current course, trying to fix the issues by adding more features, more pages to the standard, more libraries, and more complexity? That is the path of a tragedy. The traits that made the protagonists successful also bring their downfall because they can not see another way. The alternative is a redemption story where the protagonist realizes the only solution is a drastic change.”
In a reddit discussion about Carbon as a successor for C++, one of the comments notes:
“There are no replacements, just alternatives. Anyone telling you that is giving you false information.”
I agree with the above comment. We are still in the very early stages of considering alternatives. This may lead to new languages gaining attraction and others stepping down, but we are still far from seeing any clear winners. And at the same time C++ is still being very popular, highly used, including in new projects and with a huge amount of code base to maintain for the following decades. Yes, C++ has its own challenges, but the burden of proof is on the proposed alternatives, and the bar is high.
We mentioned David Wheeler and the fundamental theorem of software engineering above. Wheeler has another known quote saying: “Compatibility means deliberately repeating other people’s mistakes.” Think about it: that is smart. But a bit superficial. We all know that dropping compatibility is ignoring the past which is in many cases just impractical. The tension between novelty and compatibility with carrying technical debt that comes with old design decisions, will always be there.
My forecast is that before the great paradigm shift that would change the way we program, there is still room for at least one more generation of new leading system language. A language that would introduce meaningful improvements for programmers’ productivity and may replace C++ lead. Would it be Rust that may gain momentum? Carbon if it becomes ready for production? Or a fork of C++ like Circle? Maybe another contender like D, Zig or Nim? Or something else which is not out there yet…
If I have to currently pick, I would stay with C++, but I’m keeping my eyes open.
Additional Resources
A very good series of videos by Ginger Bill discussing Carbon:
- Carbon Language – First Impressions from the Creator of the Odin Programming Language
- Carbon Language – Who is it even for?
- Carbon Language – Final Conclusions (It’s Probably Not For You)
Can Google’s New Programming Language ‘Carbon’ Replace C++ Better Than Rust? – Slashdot
René Rebe provoking video on Carbon:
A forum discussion on Nim vs D (in NimLang site, so might be a bit subjective).
Why Modern Alternative Languages Never Replace C/C++ | by Shalitha Suranga | Aug, 2022 | Level Up Coding – requires critical reading, see also the comments to this post.
Google’s Carbon Language Might Replace C++ – levelup.gitconnected
Don’t Get Burned by Google Carbon | by Erik Engheim | Aug, 2022 – Medium
Google Launches Carbon, an Experimental Replacement for C++ – The New Stack