Ask HN: Are there any good reasons to use C++ over Rust for new projects today?
So that brings me to the question. Is there any point in starting new projects in C++ anymore?
I don’t want this to turn into a language flame-war. My question is in good faith and I do want to learn from the wisdom of the folks who comment here. People who have been using Rust for much longer than I have can offer valuable insights that I might not know. So to avoid flame-wars, let me make this question as specific as possible:
1. Is there any context in which it makes more sense to start a new project in C++ instead of Rust?
2. For someone like me who is not too experienced in Rust, what are the things I should watch out for or be careful about when starting a new project in Rust?
3. Any other free-form advice you have for someone like me who is considering making Rust my go-to language for doing new projects?
91 comments
[ 3.0 ms ] story [ 187 ms ] threadWhen you'd need to make your own Rust bindings or rely on some third-party project which may or may not be actively maintained, then C++ is more attractive.
1. I already know (some) C++
2. more mature GPU ecosystem, particularly CUDA support
I don't mind learning new languages, so CUDA was the deciding factor for me. Maybe someday as Rust's GPU support improves I'll consider a rewrite.
Other than that, Rust is a great language with a great compiler eliminating whole categories of bugs possible with C++.
Maybe it’s possible but definitely not as straightforward to use rust on iOS. Compared to C++.
The use-cases I know of basically build a library exposing the C ABI, which is slightly annoying but effective. I'm guessing you're referring to Swift <-> C++ interop?
I wasn't trying to claim that they're equivalently easy: just that they both have the same capabilities, there's nothing special that one can do that the other cannot.
On the other hand there's of course the borrow checker which means you need to think a bit more about how you do your lifetimes, which can slow you down a bit, but I find that that prevents me from writing bugs more often than not.
"There were some problems with Scala in the real world. Compared to Java it had a big learning curve, what with all the features it took from Haskell and functional programming while also keeping all the old features of Java. Some of the libraries weren't as mature as their Java equivalents or there were two equal competing libraries whereas with Java there was just one popular library for a given thing. Hiring Scala developers was an issue. Compile times were bad. Every major version of Scala (ex. 2.10, 2.11, 2.12, etc.) broke backwards compatibility so if you had something with say Scala macros that compiled in Scala 2.10 it wouldn't necessarily compile in Scala 2.11 without code changes. We had a library where the maintainer abandoned it at Scala 2.10 and we couldn't upgrade to Scala 2.11 without either taking the library out and using something else in its place or taking over the library, which just wasn't feasible. There was an issue with Scala that I've seen with C++ as well where the language is so big that different teams and different people program in different "dialects" of the language, using different subsets of language features (ex. some people used OOP class inheritance and some did not). Lots of people didn't get Monads or functional programming. But yeah, lots of places ended up going back to Java or using Node.js if they wanted to be async/reactive. "
2. Continuing on that, QT is still good for large desktop GUI projects. It doesn't seem it's well bound to Rust, and Rust is still trying to figure out their comparable UI story.
3. Ironically, in some certain circumstances, with good discipline, (And mostly interfaces that looks like C) C/C++ can compile faster then Rust.
The downside to using Rust is that its still an evolving language so you may have to refactor your code down the line. Generally Rust use case is targeted towards enterprise software, where you have lots of people working on it, and it needs to be fast, and you want to minimize chances of introducing memory bugs. For personal use, I don't think its honestly worth it tbh, it just slows you down.
Personally, I use Python and C exclusively. Its pretty easy to write C extensions to Python to handle the things you need to go fast, and then let Python handle the launching of the code. For example, I was playing around with MCTS, and I would have the tree set up in Python, and then use multiprocessing to split the tree into x processes, and each process would launch C code that did the search a lot faster. Overall the implementation was super easy since I didn't have to write the low level C code for the initial setup, with memory management and so on.
There was a recent video about using torch to compile custom CUDA kernels (https://www.youtube.com/watch?v=nOxKexn3iBo). I have implemented this for some custom data processing that I do that I previously had C code to do on the CPU, and its WAY faster using CUDA.
In rust it's mainly been nightly stuff getting merged to stable, pre-1.0, and async. Much more stable overall.
If that's what you want to do, which is a big if. I guess strictly speaking the same is true for Rust but in Rust, with it being new, it "feels" more like I should keep up (at least for me). In c++, I would mostly just not mess with old code that works...
If you hand me a pile of c++03 code that happens to compile, my confidence in it meeting both of those criteria is fairly low. If you ask the standards committee or bjarnes, what they're going to tell you is to rewrite it in modern C++, which constantly evolves.
Contrast that with rust where it's probably fine if it compiles.
The same will be true for Rust in 50 years (assuming Rust doesn't die any time soon). If they didn't think it was worth modernizing, they'd just leave C++ alone (which I think they should, but that's another matter).
For old C++, you run valgrind and a linter on it and if nothing comes up it's also "probably fine". At least it's hard for me to think of a situation where the most productive/profitable-for-buisness thing a developer can be doing is modernizing their old C++.
When you're building old code, the compiler can't check that it upholds the standard to the degree that it can for modern C++. That's why the advice is to update the code, because the tooling can't save you otherwise.
Rust by contrast guarantees that you either have a compiler/runtime bug or the issue is more narrowly localized than "potentially every single line of code". Sure, I'd like better, but it's an improvement.
Definitely not. But it's rare that so much is at stake. I would not bet my life on the borrow checker either, there's a lot of things that can go wrong in a program.
Money is of course a question of how much. Application security is just "the above". The "undefined behavior can explode your PC, travel back in time and become your father" problem is not to be underestimated. However, in cases where old code works well for years but really has some lurking bad UB, one can disable some optimizations and be conservative with compiler choice. A lot of people dislike the trend towards compilers being ever more punishing of UB and I can see their point, while it's of course hard to argue for (let alone find) a balance between performance and some robustness to ubiquitous and almost inevitable code issues.
Rust's giarantees are nice and I sure would prefer working on a modern Rust project than any C++ project, as well as a modern C++ project compared to C99-with-classes. Modernizing existing code is a different matter. I've seen very few attempts at modernizing a big and old C++ codebase, no attempts where it clearly paid off and one attempt where it went wrong...
What about C? That's being modernized too, sometimes with novelties from C++ modernization, like `nullptr`! :p
https://www.open-std.org/JTC1/SC22/WG14/www/docs/n3042.htm
The more stuff you have the more problematic (adding foot guns and making it hard to learn a language) it is to add more stuff because it all interacts. And a lot of C++ features interact in bad ways...
It seems like the bigger question is what are the goals of your project(s)? Like if gaining more experience with rust is a primary goal, then the aforementioned advantages are pretty much moot. OTOH if a project could benefit a lot from leveraging mature compilers and libraries, or if you can't afford the additional time investment associated with becoming proficient with a new language, then c++ may well make more sense.
Rust is awesome, but honestly modern c++ is quickly catching up. Rust has safety going for it, but one of the issues is that sometimes you have to be more inefficient for it (reference counting), and pay the price of code litter (Boxes everywhere). Also, realistically type safety takes time to think about (although not much). Either way, you will spend time playing type golf before your code even runs and compiles.
C++ is strictly more powerful, even ignoring the memory safety. Modern c++ with its smart pointers basically has rust ownership semantics builtin, with the option to fall back to manual memory management, which is sometimes necessary. Modern c++ has concepts, template metaprogramming (MUCH more powerful than rust), constexprs, etc. This alone, for me, has made developing interpreters and compilers much easier in C++ than Rust.
Finally, after almost a decade being a professional Haskell developer I have come to appreciate the benefit of being able to prototype fast. The truth is, type-safe languages are great for final work, but having the option to throw it all out the window to just get something done, is also really nice. In my ideal world, we would have a language with well-defined semantics for ill-typed programs (even with undefined behavior) and then an option to strict-ify the type-checking when releasing. Yes, I know rust has unsafe, and this is good, but maybe I just don't know enough unsafe rust to be efficient. I find it not obvious to use. Haskell of course has a REPL which (in my opinion) makes it easier to prototype in than both Rust and C++, so while it has type safety, the REPL makes prototyping easy. Without either a REPL or an untyped fallback, I think Rust takes more time.
One more thing... Rust has great abstractions, but unlike the Haskell world where abstractions are taken to their logical conclusions fast, it seems to me rust is more conservative in its approach (multi-param traits, for example). This seems to have worked out in terms of popularity. But for me at least, when working with Haskell, I often start to reach for yet more advanced features that really ought to work. Usually, when that feature is not implemented yet, I will find an approved GHC RFC for it, and just wait for the next version of the compiler. In Rust, it seems things move much more slowly. I have found myself endlessly frustrated with what I perceive to be weaknesses in its trait system (no existentials... :( ).
At the end of the day, both are solid programming languages, with Rust being much better for anything dealing with business logic, while C++ is better for projects involving heavy meta-programming. I have personally myself done a lot of prototyping in Haskell (due to the REPL) and then implementing the runtimes in C++. Rust I've used for one-off tools, utilities, and anything to do with high-perf async IO.
Still, the remaining big deficiency that C++ has now over more modern languages like Rust is library management. The C++ standards folks seem to say every couple of years that library management is the next big thing on their schedule for the next C++ release, but it gets delayed until later.
1. One context, which appears to be yours, is when a team or individual has extensive C++ experience.
You see, for me, learning C++ with all its decades of good/bad parts feels overwhelming, so Rust makes sense for me even if it's still the hardest language I've ever learned, but as you are already an experienced C++ dev, it might make sense to continue cpping.
I'm used to simple, standard formatting tools, packaging, dependency management (Rust is great in that sense even for beginners), so to figure out how that's correctly done in cpp in 2023 would be hard. But again, for you, it's easy, you already know all that!
Apart from that, I guess there can be libs that are great in C++ and still lacking in Rust.
Also, need to consider if memory safety is really such a big issue for you and your future project.
Look at it like Mathematics. You learn Algebra, and Trig, but Calculus is a something different. If you don't have a solid understanding of the previous, you're not going to understand the symbolic manipulation of Calculus. It then gets worse from there as you go into Differential Equations.
IMO procedural and imperative programming should be understood before trying to grasp polymorphic, object-oriented and functional programming. There is a lot of abstraction, and training of your mind to abstract is a process.
Be careful, there are purists that exist out there, and they will scream and complain, but ignore them. Don't let others control how you think. A late professor of mine once told me something I thought I understood, but it didn't hit me until years later.
"Any program written in any language that produces the correct results is a correct program."
As long as it does what it is supposed to do, it doesn't matter how you get there.
Also, code purity is myth, and those seeking it are believers in mysticism and false aesthetics. There is good code organization, but when you're up against deadlines, good luck keeping it organized.
This memory safety issue is important, don't get me wrong, but it is completely over blown. SpaceX built incredible rockets and systems in C/C++. We have external tools to check for these issues, and they still need to be used with Rust.
I recently developed an oil and gas derivative tool in Rust. IMO Rust has a long way to go. It reminds me of OCaml. I spent 2 years developing a Compliance System on DEC/OSF1 in OCaml. We made the mistake of adopting that language too early. Also, the C++ community is a lot more tolerant. A big plus for C++.
I don’t have much experience in either language, and I don’t have an opinion on which is better. I am just interested in your opinion.
Personally I think the sibling comment is pretty accurate, and rust is held back by:
- slow compiling of larger projects
- async stuff can quickly lead to very complex shenanigans
- embedded still requires you to write HAL stuff for MCUs that is supported out of the box for C
For common scenarios and platforms, Rust’s library situation did get way better really quickly.
Makes me miss go, which has channels build in, has a runtime built in, and both are generally solid. None of use flavor A for this, use flavor B for that, or write wrappers for the wrong color function.
Function colors is kind of a meme but maybe-async functions are coming.
https://lib.rs/tokio is king for std environments, https://lib.rs/embassy for no_std.
Yeah the biggest turnoff for me with Rust isn't even the language anymore, but the community surrounding it.
I realize it's mostly a vocal minority and the vast majority of Rust people, including the ones I know personally, are very nice. But boy are there some obnoxious Rust evangelists out there.
Well I completely disagree with this. The C and C++ communities seem to me personally to be a lot more "elitist", engaging in extreme pedantry or dunking on each other over knowing obscure language trivia. Both the language and the community are beginner-hostile in comparison to Rust.
Not that the Rust community is perfect, because it's obviously not - but lack of "tolerance" has never seemed like one of the problems it has.
I would also add that there now seems to be more of an emphasis around being intentional in how languages foster community. The C and C++ communities (in my opinion) became how they are not by design, but mostly by accident or chance.
Sounds cool! Could you elaborate? Would you have a website somewhere? Do you have any contacts details?
Cheers!
Please elaborate.
This doesn't mean I'm necessarily advocating for c++ or rust, but c++ definitely has advantages over rust, even if they're not just intrinsic.
C++ developers understand all of the concepts needed to easily pick up Rust. As long as it's not a quick project that will be immediately thrown away getting C++ to use Rust will be worth it.
2. Can't speak to your situation, and in any case Rust and its "developer experience" are always evolving/improving.
3. If Rust is an option, choose Rust over C++. That's an opinion, but it's quite firmly held.
Doesn't really make sense to take a productivity hit for small gains in a context where safety isn't a necessity.
Just two cents from a junior person :)
the hiring pool may be smaller, but don't believe the fear.
Developing in Rust can feel like fighting the compiler though when choosing approaches / architecture that aren't a good fit for Rust. This happens a lot when people only have little Rust experience. For example: Writing a linked list can be quite challenging in Rust due to self-referential types. With more experience in Rust, developer learn how to best structure the code so that it doesn't result in this friction.
[0]https://www.hobofan.com/rust-interop/