In some ways, C and C++ run the world. You’d never know it from all the hype about other programming languages, such as Python and Go, but the vast majority of high-performance mass-market desktop applications and operating systems are written in C++, and the vast majority of embedded applications are written in C. We’re not talking about smartphone apps or web applications: these have special languages, such as Java and Kotlin for Android and Objective-C and Swift for iOS. They only use C/C++ for inner loops that have a crying need for speed, and for libraries shared across operating systems.
C and C++ have dominated systems programming for so long, it’s difficult to imagine them being displaced. Yet many experts are saying it is time for them to go, and for programmers to embrace better alternatives. Microsoft Azure CTO Mark Russinovich recently made waves when he suggested that C and C++ developers should move to Rust instead. "The industry should declare those languages as deprecated," Russinovich tweeted.
Many developers are exploring Rust as a production-ready alternative to C/C++, and there are other options on the horizon. In this article, we'll consider the merits and readiness of the three most cited C/C++ language alternatives: Rust, Carbon, and cppfront. First, let's take a look back through the history and some of the pain points of C/C++.
C++ pain points
C++ was developed by Bjarne Stroustrup at Bell Laboratories starting in 1979. Since C++ is an attempt to add object-oriented features (plus other improvements) to C, Stroustrup initially called it “C with Objects." Stroustrup renamed the language to C++ in 1983, and the language was made available outside Bell Laboratories in 1985. The first commercial C++ compiler, Cfront, was released at that time. Cfront translated C++ to C, which could then be compiled and linked. Later C++ compilers produced object code files to feed directly into a linker.
Since then, the C++ standardization effort has been continuous, starting with the publication of Stroustrup’s 1985 The C++ Programming Language and 1990's ARM—The Annotated C++ Reference Manual. These were followed by a whole series of ANSI/ISO C++ standards, in 1998, 2003, 2011, 2014, 2017, 2020, with the next one planned for 2023. There are also intermediate technical specifications to define supplements.
Every revision to the C++ standard has added features, but none have made the language easier to learn or quicker to compile. Anyone who has built a multimillion-line C++ program understands the burden of waiting for compiles. Rob Pike cites C++'s compile time as his motivation for developing Go: “Back around September 2007, I was doing some minor but central work on an enormous Google C++ program, one you've all interacted with, and my compilations were taking about 45 minutes on our huge distributed compile cluster.” Pike's solution was to develop a new language, Go, which eventually attracted a lot of adoption, but not from C++ programmers.
I personally worked on a C++ program that was “only” 2 million lines of code. At the time, it took several hours to perform a complete compile and link on a single eight-core computer, and about 10 minutes to load into Visual Studio and resolve all the symbols. I worked around the compilation problem with automation: I had a script that pulled a fresh copy of the code from the shared repository in the dark of night, then compiled the whole thing from scratch. I worked around the slow-loading problem by boiling water, brewing tea, and drinking it with teammates every morning after opening Visual Studio. (Visual Studio has since fixed the slow-loading problem, I’m told.)
For developers seeking alternatives to C++, Rust, Carbon, and Cppfront are all strong candidates. Of the three, only Rust is currently production-ready.
Rust as a C++ alternative
The Rust-lang homepage declares three major reasons to choose Rust: performance, reliability, and productivity. Rust was designed to be fast, safe, and easy to use, with the overarching goal of empowering everyone to build reliable and efficient software.
As far as performance goes, Rust is both fast and memory-efficient: with no runtime or garbage collector, it can power performance-critical services, run on embedded devices, and easily integrate with other languages. On the reliability side, Rust’s rich type system and ownership model guarantee memory safety and thread safety—which developers can use to eliminate many classes of bugs at compile-time. For productivity, Rust boasts great documentation, a friendly compiler with useful error messages, and top-notch tooling—an integrated package manager and build tool, smart multi-editor support with auto-completion and type inspections, an auto-formatter, and more.
Supported Rust use cases include building command-line tools, compiling to WebAssembly (a way to supercharge your JavaScript), building network services, and creating software for low-resource embedded systems. Rust adoption in production is gaining steam, including use in Firefox, Dropbox, Cloudflare, NPM, Yelp, and InfluxDB IOx. InfluxDB also now uses DataFusion, a Rust native SQL query engine for Apache Arrow.
Rust has a reputation for being hard to learn, although probably not as hard as C++. A big selling point is that it’s safe by default, meaning that in Safe Rust you don’t have to worry about type-safety or memory-safety. You can also enable unsafe coding practices if you need them, using the unsafe
attribute. Sometimes, you need to dereference raw pointers, call C functions, mutate statics, or access fields of a union
. All of these are unsafe, so you have to mark them unsafe in order to use them in a Rust program. (You also should really hand-check them, since you can’t depend on the compiler to correct any mistakes you make in unsafe code.)
Carbon as a C++ alternative
The new, experimental Carbon language, announced at the CPP North meeting on July 19, 2022, is intended as a possible successor language to C++. While Carbon is nowhere close to being ready for use, it does have a source repository, a Discord, a governance model, and an interpreter that you can use online or install on macOS or Linux. It currently lacks a compiler, a toolchain, or even a complete 0.1 language design.
The stated goals of the Carbon language project are: performance-critical software; software and language evolution; code that is easy to read, understand, and write; practical safety and testing mechanisms; fast and scalable development; modern OS platforms, hardware architectures, and environments; and interoperability with and migration from existing C++ code.
The project also has explicit non-goals. Developing a stable application binary interface (ABI) for the entire language and library and ensuring perfect backward or forward compatibility are not goals for Carbon.
According to Kate Gregory, one of the project leads along with Richard Smith (of the ISO C++ standards committee) and Chandler Carruth (a principal software engineer at Google), letting go of backward compatibility frees the project to make positive changes that wouldn’t be allowed in the C++ language, with the major benefit of reducing technical debt. In place of backward compatibility, Carbon will offer tool-based version upgrades and C++ migration. Tool-based upgrades and migration sound a lot better than the excruciating and lengthy manual upgrades C++ developers are required to do with every major change to the language.
There’s a lot to absorb in the code example below, which is from the Carbon repository. I’ve added comments to help.
//packages are namespaces as well as units of distribution
//Nothing in Carbon goes into the global namespace, unlike C++
//There is only one api file per package. Other files are impl
package Sorting api;
//fn declares a function
//[T means the parameter type T is generic
//Note the change from <...> to [...] for generics
//:! Means the passed type is checked at compile time
//Comparable and Movable are attributes of the generic T
//Slice hasn’t been fully specified, but think Go slices
//-> is a return value type
//i64 is a 64-bit signed integer type
//var declares a mutable variable
//& is the address-of operator, as in C/C++
fn Partition[T:! Comparable & Movable](s: Slice(T))
-> i64 {
var i: i64 = -1;
for (e: T in s) {
if (e <= s.Last()) {
++i;
Swap(&s[i], &e);
}
}
return i;
}
//let declares an immutable constant r-value
fn QuickSort[T:! Comparable & Movable](s: Slice(T)) {
if (s.Size() <= 1) {
return;
}
let p: i64 = Partition(s);
QuickSort(s[:p - 1]);
QuickSort(s[p + 1:]);
}
For more Carbon code examples, see the language design document and the Carbon explorer test data.
What does Stroustrup think of all this? Not much, at this point. “Carbon is so new and under-specified that I can’t really make meaningful technical comments.”
Cppfront as a C++ alternative
Herb Sutter has served for a decade as chair of the ISO C++ standards committee. He is a software architect at Microsoft, where he’s led the language extensions design of C++/CLI, C++/CX, C++ AMP, and other technologies. With Cpp2 and cppfront, Sutter says his “goal is to explore whether there’s a way we can evolve C++ itself to become 10 times simpler, safer, and more toolable.” He explains:
If we had an alternate C++ syntax, it would give us a "bubble of new code that doesn't exist today" where we could make arbitrary improvements (e.g., change defaults, remove unsafe parts, make the language context-free and order-independent, and generally apply 30 years' worth of learnings), free of backward source compatibility constraints.
Sutter worked on the design of “syntax 2” (Cpp2) in 2015 and 2016, and since 2021 has been writing the Cppfront compiler to prototype all the ISO C++ evolution proposals and conference talks he’s given since 2015. The prototype now includes the alternative syntax 2 for C++ that enables their full designs including otherwise-breaking changes.
Sutter’s Cppfront regression suite includes a couple dozen examples of mixed C++ and Cpp2 code, and another couple dozen examples of pure Cpp2. As with the original Stroustrup Cfront, Sutter’s Cppfront is a bridge to enable Cpp2 development and experiment with the new syntax until it’s possible to compile Cpp2 directly to object code.
Rust, Carbon, or Cppfront?
Rust, Carbon, and Cppfront all show promise as C++ alternatives. For Carbon, we’re probably looking at a five-year development cycle until it’s released for production. Cppfront might be available for production sooner, and Rust is already there.
All three languages are (or will be) interoperable with C++ at a binary level. That implies that all three languages could allow you to make gradual improvements to existing C++ programs by adding new non-C++ modules.
In the case of Cppfront, mixing C++ and Cpp2 source code is already implemented, at least partially, and is included in Sutter’s regression suite. Carbon’s tooling will include automatic migration of C++ source code. An open question is whether that will migrate 100% of your C++ code, or require you to manually rewrite some percentage of your code that would otherwise perform badly, violate Carbon standards, or require you to mark it as unsafe should you want to leave it alone.
Rust already demonstrates memory safety. You literally can’t compile Rust code that will violate memory safety unless you mark it unsafe. Carbon and Cppfront will certainly implement memory safety mechanisms. We just don’t know yet exactly what they will be.
Rust isn’t terribly easy to learn, even if you know C++, although I’m told that learning Rust is actually a little easier than learning C++ if you’re starting from scratch. Nevertheless, C++ and Go programmers usually manage to pick up Rust in a week or two.
What we’ve seen of Cpp2 from Herb Sutter makes it clear that C++ programmers will find it a relatively easy transition, even though the C++ generated by Cppfront is currently fairly ugly. Carbon’s C++ conversion tooling should enable a side-by-side editing tool, much like the IntelliJ support for learning Kotlin by converting existing Java code.
Ultimately, as Stroustrup implied in his comments on Carbon, we’re going to have to wait and see how each language and its tooling play out.