DEV Community

Cover image for What Does C++ Do That Rust Doesn't?
Ben Lovy
Ben Lovy

Posted on

Rust vs C++ What Does C++ Do That Rust Doesn't?

I want to preface this by saying these are my two primary languages. I have a healthy respect for both and plan to focus on both regardless. I know this is a provocative question, and I am a beginner in both languages.

I'm not talking about stuff where you're supposed to use JavaScript or C# or something - even though Rust is actually kinda okay at those too and improving all the time. I'm not even talking about C, even though I think eventually we might be able to have that conversation too. I'm specifically asserting that Rust could conceivably compete head-to head with C++.

That said, as I learn more about C++, I learn more about how much I don't know about both C++ and programming in general. From my perspective, the Hindley-Milner-inspired type system is a perfect match paired with the granular control over memory for the kind of data manipulation Rust is targeting. I am more than willing to be shown why I am wrong.

I recently posted about a Rust tree I implemented with a workaround for how Rust is restrictive, but the very first alternative I mentioned was unsafe. Of course, there is always the need to directly manipulate memory. Many standard library tools are by nature implemented in unsafe Rust, with a safe API written that's been vetted by the talented Rust team and the OSS community at large. There are many lib*-sys crates that are essentially the same thing. Any FFI with C will include unsafe raw pointers.

That's how any tool, OSS or proprietary, is deemed "safe", though, right? Smart people look at it?

I see talk of templates with a reverence, but to me they're a clunkier Rust trait. What can you do with templates that Rust traits + macros can't? Speaking of which, Functors in OCaml? Jane Street is making a solid case for that tool even over Haskell or C++. OCaml itself is an amazing language for UNIX/Linux programming. C++ is cemented, but new code is written all the time. Am I off the mark with where C++'s power lies?

Why not, all memes aside, write all brand new applicable-domain software in Rust, and write Rust interfaces where needed?

I understand that C++ imposes fewer restrictions by default, allowing people to override the machine where people know better. I don't know that I'm sold on why that precludes a new foundational language that's an improvement over what we have, and why Rust isn't it.

Photo by Edvin Johansson on Unsplash

Latest comments (80)

Collapse
 
__sin_ns profile image
_sin.ns

Rust carries the elegance of Haskel, capabilities of Scala and modern C++ and power and speed of C yet some concepts (e.g. ownership) are of its own and are unheard of in any other language. With due respect to C++ and the community around it, the question must be the other way around "what's in Rust which is not in C++"... Success of a language in modern times is a function of the depth of support by corporate houses and not just community enthusiasm...

If a language is capable, it will eventually find it place... Rust's engineering team is a world class group of language engineers not to mention the vibrant community which loves Rust and can trade anything for it.

For a non opinionated view, see this answer from D-language architect, another powerful language: qr.ae/pN212s

Collapse
 
angularnodejs profile image
AngularNodeJS 🚀 • Edited

I was curious to see what the trend is for these programming languages in the last 5 year.

I'm actually surprised people are still more interested in C/C++ these days with Golang and Rust being on the hype train.

trends.google.com/trends/explore?d...

Collapse
 
shawarma profile image
S. Sharma

Not a Rust or C++ programmer, but I’ve seen similar comparisons between Go and C (and I’ve used both), and there’s this same dichotomy of “C is dead, Go reigns supreme” and “C is still useful, Go is dead/just another language.”
Whatever you can do in Go, you can do it in C probably much quicker (yes there are exceptions, but for the most part this is true), but there are also many applications that are more efficiently written in Go AND are more concise than C (again, there are exceptions, but for the most part this is true).
I think we can extend this argument to Rust and C++ as well. There are use cases when writing Rust code is probably better than writing C++ and vice versa. It just depends on what you’re writing. I doubt that C++ will go away soon, but i wouldn’t be surprised if it became confined to maybe a few use cases.

Collapse
 
delta456 profile image
Swastik Baranwal

Nice post, I think Rust cannot really replace C++ because it's there for many years but Microsoft is forking Rust to make a new programming language so I think Microsoft is/will ditching C++ which uses a lot of things from C++. Like most Windows Applications are written in it.

Collapse
 
juzzlin profile image
Jussi Lind

In my opinion it will be C++ that'll evolve and replace itself. Microsoft and Google have created tons of "cool" programming languages that they always ditch even themselves after a while. What's the point?

Collapse
 
delta456 profile image
Swastik Baranwal

It's like saying that we don't and shouldn't use C but it is needed to run on all hardware.

Collapse
 
deciduously profile image
Ben Lovy

Agreed, replacement is not likely or even probably warranted, but symbiosis could be.

Collapse
 
delta456 profile image
Swastik Baranwal • Edited

I think Microsoft is trying to combine Rust and C++ into one which would be amazing.

 
codemouse92 profile image
Jason C. McDonald

It's worth noting that C++ didn't kill C, either. ;)

So I think you're right on that nothing is likely to "kill" anything else.

Collapse
 
codemouse92 profile image
Jason C. McDonald

Sorry to cross-post to another of my own articles, but I've been pondering this for a few days, and the conversation keeps reminding me of this:

Collapse
 
deciduously profile image
Ben Lovy

This was a fun read!

After all, Linux is still written in Rust, and it works great despite that language's terrible error handling.

Just curious - is this an actual commentary on your thoughts about Rust error handling in today's context, or merely a commentary on how our understanding should be expected to evolve? At least comparing to C++, Rust's Result is a solid win over try/catch for me.

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited

It's more of an ironic statement. Since Rust's error handling is reputed to be so cutting-edge now, like try/catch was in its day, I'm imagining that it could be considered "clunky" and "terrible" in 30 years.

Collapse
 
shalokshalom profile image
ShalokShalom

C++ is already known to the people. People are afraid if new stuff. Thats it

Collapse
 
juzzlin profile image
Jussi Lind • Edited

Well...I tried to study Rust, but soon gave up. It's just too different and the ecosystem is not there. Has nothing to do with being afraid.

When talking about C++, people should realize that C++11 is completely different than the legacy C++. There's not much benefit in Rust in my opinion anyway.

Collapse
 
shalokshalom profile image
ShalokShalom • Edited

So you dont know the language and you think you can say it has no benefit to Rust, despite that industry legends say so and there is actual evidence for it?

100% guarantee of no occorance of the most security relevant issues is no benefit?

Increased understanding of how a proper memory management can look like neither?

Thread Thread
 
juzzlin profile image
Jussi Lind • Edited

I have never had any issues with the "unsafe" memory management of C++. Rust advocates make it sound like every C++ application does nothing but crashes and leaks. Of course that's not the case. With RAII and smart pointers memory management is a non-issue.

Btw: zdnet.com/article/google-programmi...

Fuchsia supports C++ fully. Rust - not so much. This is one example of the ecosystem problem.

I'm not saying Rust doesn't have the features it has. They are just not that valuable FOR ME.

Collapse
 
angularnodejs profile image
AngularNodeJS 🚀 • Edited

Javascript and Web ASM is going to kill this debate of what language to use in the near future as the JS Engine will move out of the browser and become native with cross-platform support and access to native OS APIs.

When in doubt, always bet on Javascript!

I coded in C++ for 10+ years, I don't miss it, it's too low-level and suffer from having to write tons of your own code. Rust, I've been told is not a simple language to learn for most web programmers. So forget adoption from web developers.

I personally wouldn't waste my time learning Rust as much as I don't care for C++ and how unproductive that language is. I'll just wait it out and be super productive in JS writing native cross-platform code compiled to Web ASM.

Here is a nice talk about what's coming: youtube.com/watch?v=Qn_4F3foB3Q

Collapse
 
deciduously profile image
Ben Lovy • Edited

Interesting take.

not a simple language to learn

Nor is C++, but lots and lots of people have anyway.

forget adoption from web developers

Perhaps, but I don't think web developers make or break the issue here. AssemblyScript and such projects do seem interesting, but I am curious if they will be adequate to completely replace lower-level languages used to produce WASM today. WASM is a low-level concept, and having a more granular level of control in the source language is often a good thing here. Writing all your WASM in a language that lacks facilities for this might work for some domains, but I'm not convinced you can blanket-replace C++/Rust here with something like JS. I could very easily be wrong, but while JS can product WASM, can it actually produce highly optimized, tightly controlled WASM?

I don't think every developer will need this, most applications will be perfectly happy without it, but I do think some of us will.

All that said, too, while I agree WASM is game-changing tech, it still only addresses a subset of where C++ proliferates today. I think this is only addressing one part of the tool.

Collapse
 
angularnodejs profile image
AngularNodeJS 🚀 • Edited

Yes WASM bytecode will be highly optimize, both using static analysis and dynamic branch-prediction as done in V8 Engine and SpiderMonkey JS Engine. Even right now execution time for hot-optimize JS is close to C++ code.

Here is a talk from Google JS vs C++: youtube.com/watch?v=aC_QLLilwso

The Moz technical committee along with other peoples are working on defining low-level system APIs that will be uniform and standardize. We will get true cross-platform support.

The main point is, we will finally have cross language interoperability. I will be able to use Python modules, or C/C++ libs with my JS code and likewise other language will be able to use NPM module. Basically everything will be compiled down to a WASM package, module or whatever they end up calling it.

JS with WASM will never replace something like C/C++/Rust for low-latency system coding, but how many people code drivers? or ultra low-latency systems? The typical developer will want to code some application or server most of the time. Most all will go with the easier dominant programming language to code in. Even the hype train at Mozilla for Rust has died and they stop pushing Rust as the language for the web.

WASM is going to be game changer, both in and out of the browser. Most likely you won't notice any changes, as new build tool and do the compiling for you.

Thread Thread
 
deciduously profile image
Ben Lovy • Edited

Points all well taken, but I want to code drivers! And compilers, and kernels. If I could do so in Rust, I'd be much happier than in C or C++.

There are many, many types of programming.

I will be able to use Python modules, or C/C++ libs with my JS code and likewise other language will be able to use NPM module.

Right with you there. WASM is a game changer. I'm just not sure that makes Rust a waste of time...maybe even the opposite.

Thread Thread
 
angularnodejs profile image
AngularNodeJS 🚀

Let me take that back What I meant to say is, knowing what's coming, there is no reason to switch to different programing language. They will all run at "almost" the same speed as WASM bytecode.

Sure if you want to re-write the OS in Rust, then that might be a project you want to take on. It won't be any safer or bug free.

Whatever you do, never ask Linus why Linux is coded in C and not C++ :-D

harmful.cat-v.org/software/c++/linus

 
deciduously profile image
Ben Lovy • Edited

Isn't that just different placement of the error

Yep, 100%. The difference is conceptual, not practical. The Rust Node<T> is not generic over any type T, it is only generic over types T that implement ==. Any attempt to instantiate it with a type that does not is actually a type error. Traits further qualify and constrain types. In C++ it's not a type error, it's a method resolution error. As a programmer, when building this object, I do really mean to say "generic over types that can be compared for equality", not "generic in general and I promise later I'll tell you how to do it", even though where we get in the end is functionally equivalent. As it's being used, an inadequate T class is actually not part of the "type" of this object.

That feels to me "more correct", or at least more expressive. Practically, though, yeah, maybe it doesn't make a difference.

C++ is kinda simple like thta: if you don't use it, you don't pay for it

Rust strives for this as well, the difference here being that any type used in this object will use it, and the compiler is capable of making sure everything is in order before even starting down that road.

Thread Thread
 
danielbsmith profile image
Daniel Smith

Isn't that just different placement of the error

I don't think this is completely true. It is at least simpler to constrain generic types more strictly than the current implementation requires in Rust. You may wish to add extra constraints on the type to give yourself implementation flexibility without needing to break callers. For example, if the current implementation only requires equality but I only want to accept types that implement ordering, that's pretty trivial in Rust. I would guess you could use some if 0 trick in C++ to use the operator but not impact the implementation, but that obscures intent at a minimum.

Thread Thread
 
danielbsmith profile image
Daniel Smith

Conversely, (stable) Rust does not have the equivalent of SFINAE. Specialization is available in nightly, which is pretty similar. I've seen this come up comparing Abseil Swiss Map and Hashbrown maps. The former will usually do the most efficient thing by default, but the latter requires the subtle RawEntry API to do things like lookup or insert without copying unless I'm actually inserting.

 
deciduously profile image
Ben Lovy

In terms of lines of code, it's one line shorter.

That's not necessarily what I'm getting at in terms of programmer ergonomics, but it is an interesting observation, thanks for pointing that out. I think it will take me a little longer to find an example to illustrate the mismatch here in functionality.

Runtime?

My turn to pull the half-asleep card - definitely didn't mean runtime, just successful instantiation. Control flow advances to the offending method call with an object that will not succeed, and the equivalent Rust kicked out the error at object creation itself.

Collapse
 
tuned profile image
Lorenzo (Mec-iS)

C++ templates were introduced in C++11 and I still don't know if are inspired or instead inspired generics in Rust. Reconstructing the historical process is also somehow important.

Collapse
 
deciduously profile image
Ben Lovy

C++11 introduced variadic templates, but non-variadic templates existed before then. Each successive release has extended the feature set significantly, though. Generics are seemingly universal, I think it would be tricky to pinpoint a "chicken-or-egg" moment between Rust and C++.

 
deciduously profile image
Ben Lovy • Edited

The EOL date is officially set (I haven't paid attention - we might've passed the date as well)

Python 2 EOL is in 10 days - Jan 1, 2020 :) Great example.

The code examples are much appreciated, this is indeed what I was missing:

template <typename NA, typename NB>

However, that still kinda feels like, well, a "clunkier Rust trait". Which I absolutely concede is a matter of opinion. My concrete criticism is that C++ will still happily instantiate your template with whatever you ask for, and then fail at the first offending method call. Your type has been existing fine in your running program until then. Rust is able to prevent nonsensical types from being instantiated in the first place, so you never get to a runtime condition where you're looking up these template operators at all.

Collapse
 
deciduously profile image
Ben Lovy

Kill/replace hyperbole

I definitely didn't intend for this post to head that direction, either, it's an unproductive and uninteresting conversation. I'm more curious about why I might be incorrect about my assumption that, all else equal, Rust could plug in to any situation where C++ is currently deployed and hold its own.

 
deciduously profile image
Ben Lovy • Edited

Maybe rust gains the high-ground in 10 years, and gets thrown back down in 15 by a new language to fix all the things someone sees as a problem with Rust

Or we just all stick to C++40! Very fair point.

The Linux kernel, said to be written in C, is in fact written in C, C++, Assembly, Objective-C, and possibly more under the "other" category that are programming languages and not meta languages.

Of course, any sufficiently complicated task will require a rich set of different tools fitted to different parts of the problem, but to me the C++ needs are also met by Rust.

(assuming we haven't wiped ourselves out by then)

Oof. Altogether too fair :)

PartialEq seems to be exactly like operator==, just with a different syntax

Yep, more or less. The benefit to me is in using them. If you were to write a binary search tree, your Node might look like this:

template <class T>
struct Node
{
    T val;
    Node *left;
    Node *right;
}

Now you can build a Node<int> or Node<double> or whatever, but in your insert() method you will assume that T overloads both ==/<. Is there a way in C++ to tell the compiler about this? In Rust, you constrain it:

struct Node<T>
where
    T: PartialEq + PartialOrd
{
    val: T,
    left: Rc<RefCell<Node<T>>>,
    right: Rc<RefCell<Node<T>>>,  // or whatever pointer type
}

Now this code won't compile unless your T is an appropriate type. It serves as both documentation and stronger static analysis. As far as I'm aware, all you get is the failiure to build when your code attempts to use a method like operator== that doesn't exist for your current T class.

Any unimplemented cases of operator== default to a standard implementation

This is precisely the behavior I feel is inferior to Rust, which will fail to compile with a friendly message telling you to implement it specifically instead of guessing and failing.

the programming community in general has to see that SomeLang has better features than SomeOldLang.

I think this does cut to the core of my question. From my (completely novice) perspective, that seems to me like what we are working with. General consensus, though, is clearly that that's not the case. I understand the arguments for C++'s proliferation - it's of course not going anywhere, but I want to understand more about why Rust isn't actually as cracked up as it seems.

Collapse
 
deciduously profile image
Ben Lovy • Edited

Thanks, this is a great response, but I do think we've mismatched on a few points. First:

Arguing over which programming languages are the best and likely to beat others isn't going to be productive

That's not at all the spirit of this post, though I see how it could be taken as such. These are my two favorite languages. I do very much like Rust, and I very much like C++, and will continue to work with both for years to come. This question is more a thought experiment about inherent technical merit and domain fitness than about changing the landscape of software development.

Operating systems are also written in (or at least contain) C/C++

They do, yes, but what I'm drilling for is whether there is something inherent in C/C++ that Rust could never possibly replace, or whether this ubiquity is historical. The redox experiment is doing a solid PoC already, imagine what it'd look like with another 20 years of ecosystem development.

Templates aren't directly about inheritance, but rather about generalization

I also agree it's a bit confusing how I wrote it up, but I do think I understand what templates are and how to use them - they're a core mechanism for building abstractions. I brought up Rust macros and OCaml Functors for the same reason, they're how to build toolkits for programmers and grow in a sane way. The equivalent in Rust is just the fact that you are able parameterize a type, you don't need to write template <typename T> first. Classes and structs drive OOP C++ programming, but when comparing to how code is crafted in Rust the generic programming properties of C++ are a more direct fit. For that the core mechanism is templates.

Rust traits go a little further. For instance, when you use that type, as far as I know there is no way to specify that you expect the type to overload operator==. In Rust, you constrain T to types that implement PartialEq, and that alone feels worthwhile to me. I don't know of the equivalent for C++ beyond just using it correctly. I don't fully understand them, but I think C++20 concepts may address this, but I'm not sure what the answer is in C++11 (or earlier).

All in all, I agree. Languages are preferences, and at the end of the day it doesn't matter what you use as long as it gets your job done well.

Collapse
 
lenkite profile image
Tarun Elankath

Ridiculously late reply, but I just came across this now. C++ 20 now has formalised concepts that can apply constraints to generic types, so this gap has been addressed.

Rust AFAIK is still missing fold expressions and variadic templates. Once you get used to these features, you wonder how did you live without them. Also, I like exceptions and method overloading. C++ also has std::error_code for those who wish to have exception less functions. The C++ FS library provides both throwing and non-throwing variants of their API.

As a polyglot programmer (forced to be one thanks to several projects), I found Rust to be the MOST complicated language - yes, even more complicated than modern C++ to learn. I learned C++ seriously only after C++ 17 and frankly all the hoopla about it being difficult was overhyped. I am actually a bit faster in C++ than in Java.

The Rust borrow checker twists my head and my code and I don't appear to focus on the problem I am attempting to solve anymore. I prefer the clean, easy, automatic memory management of modern C++ and simply following recommended safe programming practices via Core Guidelines. I can run static analysers independently of my main programming flow to avoid breaking my immersion and they catch all my bugs without interrupting me. Coding Rust gives you anxiety sometimes - you need to please the Emperor. Also, Rust compiles slower than C++.

Also Rust ecosystem is perennially in Churn - what compiled some months ago no longer compiles today. Libraries keep breaking. Stuff keeps changing all the time. C++ is well-specified and standardised language with a stable and well-defined standard library with multiple implementors. And you have a stable ecosystem with well documented libraries. And admittedly cargo is quite good but, I only started using C++ after CMake/Conan/Vcpkg won the build/packager tools war, so I never faced the old autotools+make headache that folks used to complain about.

Rust doesn't have a spec and still has only one implementation and is backed by a foundation that kicked out many of the engineers working on rust.

Frankly, Rust sounds like a lot of hype and fluff to me. But I am just an average programmer joe who is likely bad at predictions.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.