Comparing Rust to Carbon Please consider subscribing to LWN Subscriptions are the lifeblood of LWN.net. If you appreciate this content and would like to see more of it, your subscription will help to ensure that LWN continues to thrive. Please visit this page to join up and keep LWN on the net. Safe, ergonomic interoperability between Rust and C/C++ was a popular topic at RustConf 2025 in Seattle, Washington. Chandler Carruth gave a presentation about the different approaches to interoperability in Rust and Carbon, the experimental "(C++)++" language. His ultimate conclusion was that while Rust's ability to interface with other languages is expanding over time, it wouldn't offer a complete solution to C++ interoperability anytime soon — and so there is room for Carbon to take a different approach to incrementally upgrading existing C++ projects. His slides are available for readers wishing to study his example code in more detail. Many of the audience members seemed aware of Carbon, and so Carruth spent relatively little time explaining the motivation for the language. In short, Carbon is a project to create an alternative front-end for C++ that cuts out some of the language's more obscure syntax and enables better annotations for compiler-checked memory safety. Carbon is intended to be completely compatible with C++, so that existing C++ projects can be rewritten into Carbon on a file-by-file basis, ideally without changing the compiler or build system at all. Carbon is not yet usable — the contributors to the project are working on fleshing out some of the more complex details of the language, for reasons that Carruth's talk made clear. " It's always a little exciting to talk about a non-Rust programming language at RustConf, " Carruth began, to general laughter. He has worked in C++ for many years, and has been working on Carbon since the project started in 2020. Currently, he is paid for his work on Carbon as part of Google's languages and compilers team. He briefly showed some research from Google indicating that the majority of the security vulnerabilities it deals with could have been prevented by memory-safe languages, but he didn't spend too long on it because he expected the audience of RustConf to be well-aware of the benefits of memory safety. The thing is, there is a lot of existing software in the world written in C and C++. There is no magic wand to make that software go away. Migrating any of it to memory-safe languages will require those languages to integrate with the rest of the existing software ecosystem, he said. Interoperability is not just nice to have — it's a key part of what makes adopting memory-safe languages work. Rust already has several tools to make interoperating with C/C++ code feasible. Carruth listed Rust's native foreign-function interface, bindgen and cbindgen, the cxx crate, and Google's own Crubit. But he claimed that none of these are really good solutions for existing C++ software. He defined software as existing on a spectrum between "greenfield" (new code, not tightly coupled to C++, with strong abstraction boundaries) and "brownfield" (tightly coupled to existing C++, with a large API surface). Greenfield software is relatively easy to port to Rust — it can be moved one module at a time, using existing binding tools. Brownfield software is a lot harder, because it can't be easily decomposed, and so the interface between code written in C++ and code written in Rust has to be a lot more complex and bidirectional. The question, Carruth said, is can Rust ever close the gap? He doesn't think so — or, at least, not soon and not without a monumental effort. But Rust is not the only approach to memory safety. Ideally, existing C++ code could be made memory-safe in place. Lots of people have tried that, but " the C++ committee is probably not going to do it ". There's no way to successfully add memory safety to C++ as it is, he said. There are several languages that have managed a transition away from a base language into a more capable, flexible successor language, though: TypeScript is an evolution of JavaScript, Swift is an evolution of Objective-C, and C++ itself is an evolution of C. Carruth thinks that Carbon could be a similar evolution of C++ — a path to incremental migration toward a memory-safe language, prioritizing the most entrenched brownfield software. Rust is coming at the problem of memory safety from the greenfield direction, he said, and Carbon is coming at it from the other side. That makes Rust and Carbon quite different languages. A closer look The real focus of his talk was on showing where those differences are, and where he thinks each language can learn from the other. The syntaxes of Rust and Carbon are " not wildly different "; the differences he wanted to focus on were more abstract. For example, in Rust, a compilation unit is an entire crate, potentially composed of several modules. Therefore, it's allowed for modules to reference each other in a cyclic way, and that just works. That isn't something Carbon can support because " existing C++ code is often oddly dependent " on the ability to compile individual files separately. So, Carbon inherits C++'s model, complete with forward declarations, (optional) separate header files, and more complexity in the linker. This makes Carbon's model more complex, but that complexity doesn't come from nowhere — " it comes from C++ ". Another example is the difference between traits and classes. Rust traits and Carbon classes are not that different, syntactically — Carbon just writes methods inside the struct definition, while Rust writes them separately — but they have major conceptual differences. Carbon has to handle inheritance, virtual functions, protected fields, and so on. " This stuff is complexity that Rust just doesn't have and doesn't have to deal with. " Carbon wants to meet C++ APIs where they are, he said. One can even inherit across the C++/Carbon boundary. This sort of difference is pervasive, he said, and comes up in all parts of the language. Operator overloading, generics, and type conversions are all more complex in Carbon. Why do it this way? Why is all of this additional complexity worth it? To explain, he showed an example of a hypothetical but not unusual C++ API: int EVP_AEAD_CTX_seal_scatter( const EVP_AEAD_CTX *ctx, std::span out, std::span out_tag, size_t *out_tag_len, std::span nonce, std::span in, std::span extra_in, std::span ad); The example was adapted from a real function in the BoringSSL cryptography library. Each std::span is a combination of a pointer and a length. The main problem with faithfully representing it in Rust is actually not visible in the code itself; the documentation for this function explains that out must either be the same pointer as in , or a completely non-overlapping piece of memory. When the pointers are the same, the function encrypts a given plaintext input buffer in place. Otherwise, the encrypted output is written to the output buffer without disturbing the input buffer. None of the other pointers are supposed to alias. Carbon is still a work in progress, but the current plan for expressing APIs like this in a machine-checkable way is to use "alias sets". These would be annotations showing which pointers are permitted to alias each other, and which ones aren't. The resulting Carbon code might look like this: fn EVP_AEAD_CTX_seal_scatter[^inout]( ctx: const EVP_AEAD_CTX ^*, out: slice(u8 ^inout), out_tag: slice(u8 ^), out_tag_len: u64 ^*, nonce: slice(const u8 ^), input: slice(const u8 ^inout), extra_input: slice(const u8 ^), ad: slice(const u8 ^)) -> i32; Here inout is a name given to a particular alias set, and used to annotate out and input . All of the other pointers in the function signature don't have an alias set specified, so the compiler would ensure they can't alias. Trying to represent this API in Rust just doesn't work. The language never lets mutable references alias each other, so you end up having to have two separate wrapper functions with different signatures for the in-place case and the copying case. Rewriting the module that contains this function in Rust would become a complex process, intermingling the simple translation of the actual code with the refactoring of the interface. The power of Carbon for interoperability, Carruth said, is that it lets you decouple these things and do them as small, separate steps. He showed another example of a C++ program that was actually memory-safe, but that wasn't compatible with Rust's lifetime analysis. No computerized analysis of memory safety can ever be perfect, so Carbon presumably won't be able to do much better here — but in Carbon, patterns that the compiler cannot prove to be memory safe can be turned into a warning instead of an error. This focus on meeting C++ where it is makes Carbon a different language. It ends up being specially tailored to interoperability and gradual migration, which isn't free. This makes the language more complex than it could be otherwise, and Carruth doesn't think that's the right tradeoff for every language. But if the goal is to have memory-safe software throughout the software ecosystem, he thinks that there needs to be room for Rust and Carbon both. This isn't a competition between languages; it's two different languages working together to cover the widely divergent needs of different projects. Index entries for this article Conference RustConf/2025 to post comments