Dunno. Young devs can pick basic Rust constructs fast but when it comes to complicated stuff where performance is critical... There must be raw talent and lot of grind. IMO it's easier to write super complex stuff in C++ than in Rust as there are just too many cognitive things to keep in mind in Rust to even compile. C++ for talented folks makes life easier there. Like JavaScript, yet another language written for bad to average developers to keep them from shooting themselves in the foot.
> in Rust as there are just too many cognitive things to keep in mind in Rust to even compile.
That hasn’t been my experience. Rust (the language) doesn’t seem to get any more complex as programs get bigger. Lifetimes, while complex in isolation, tend to compose really well.
Most of the pain of learning rust seems to be experienced up front. (Well, other than async but I don’t consider that ready yet).
In comparison, my experience of C++ was that it has way more “spooky action at a distance”. A bug in one part of the code will cause problems in another totally unrelated part of the code. I’ve had memory bugs in C++ which took weeks to track down. Maybe C++ has gotten better - I haven’t touched it in over a decade. I haven’t wanted to. And I can’t see many reasons I’d pick it up now that I know rust.
If you didn't use C++ with the RAII paradigm, and had to write your own new/delete, your previous C++ experience isn't representative of the complexity of dealing with C++ since C++11. The new standards are a massive upgrade, and now a lot of other things are starting to get major quality of life improvements too (eg. template metaprogramming)
This is a really good point. Just like the Great and Powerful oz telling us not to look behind the curtain or you'll see a goofy old man - C++ is quite mighty if you don't look over there at the other stuff.
Did rust have a GC at some point pre-1.0? Interesting.
Not sure how limiting the discussion of a language to just the features included in the 3rd standard and forward makes sense. Particularly when the old stuff is still present and valid in the later standards.
Just because you want to use some convention curtain off some area of the language doesn't mean it's not there.
This came 2 years after C++11 was finalized, which introduced RAII memory management, threads, range loops and much more, and is the basis for modern C++.
Of course, there are pros and cons to keeping backwards compatibility with old code. Personally I think it's an amazing technical achievement that the same code written in 1987 still works. Particularly for numerical work there are a lot of libraries that would be a massive pain to rewrite correctly, just getting them off of Fortran was an achievement.
In terms of new and old standards coexisting in the same code, of course it isn't preferable, but it is possible which can enable many use cases, eg. in place upgrades. Forcing rewite-the-world is what caused the Python 2 --> 3 migration to be such a mess.
And if you really don't want old features, there are linter rules and compiler warnings which do a great job for this.
There's a 3rd option between "break the world" and "keep everything the same forever".
Look into rust's editions. Short version: any compilation unit[1] can declare which edition it is written for. The code in that unit must be valid under the rules of the edition, but different units with different editions can be compiled into a larger program.
[1] the compilation unit in rust is a crate. That doesn't mean it has to be put into crates.io, just that it has to be cordoned with its own Cargo.toml and any non-public structs/functions/etc will not be accessible from outside the crate.
This is, of course, due to the fact that Rust doesn't have a language specification, just a compiler implementation. If an old version of the compiler has a bug, using an old edition will still have that bug. Contrast this with C++, using an old feature you can still benefit from the latest bugfixes, optimisations, target architectures and instruction sets.
With the new GCC Rust work I believe a new solution will need to be found, and it will end up more similar to the situation with C++.
>IMO it's easier to write super complex stuff in C++ than in Rust as there are just too many cognitive things to keep in mind in Rust to even compile.
Surely you can describe this with more than a throwaway sentence, given that more and more people are seeming to experience the opposite.
>Like JavaScript, yet another language written for bad to average developers to keep them from shooting themselves in the foot.
Nobody would describe JS this way - the entire existence of that language is filled with projects attempting to make it better for "bad to average developers" because it is certainly not what you're describing.
> IMO it's easier to write super complex stuff in C++ than in Rust as there are just too many cognitive things to keep in mind in Rust to even compile.
It keeps you from compiling (many of) the bugs you'll happily write and deploy in C++. I don't think there's really much practical difference in "cognitive load" between modern C++ (which is painfully complex in ways that are largely not even useful) and rust. C++ just lets you pretend it's lower and you ship more bugs.
Imo, writing rust is like the best parts of writing C++ with a stern but helpful assistant.
Sure, but don't forget the inherent trade-off - Rust allows you to write safer code at the cost of getting in the way. It simplifies some things and makes other things very complex. It empowers average devs that can suddenly write certain types of system services easily and be reasonably sure they work as intended, but it gets in the way of advanced devs writing core systems.
This sounds an awful lot like how everyone thinks they're an exceptional driver and everyone else is bad. Reality is no one's actually that great at piloting a ton of metal at speeds their brains can't keep up with in an uncontrolled environment.
Anyways, unsafe exists so that if rust is genuinely in your way you can still do what you need to do.
Even C++ requires inline/linked assembler code in certain system cases to squeeze out maximum performance - why would you think Rust is an exception? It has nothing to do with elitism.
If we're talking about raw performance then I'm baffled at what you're talking about to begin with. Rust can link with assembly just as well as c++ and I believe inline asm was stabilized a while ago. Otherwise it's llvm doing the heavy lifting on optimization so clang++ or rust is not much different.
Other than the fact that rust can rely on much much stricter aliasing rules and do a bit better on some optimizations because of it.
Usually when people talk about rust getting in their way they mean the borrow checker, which you can ask to get out of your way and it will still prevent bugs around the unsafe code. Bugs that "advanced programmers" are also prone to, especially around concurrency.
The idea that some programmers are so good they don't make simple but consequential mistakes in code that deals in concurrency and memory management is absolutely elitism.
There is no programmer on the planet who can't benefit from the borrow checker, and if there are any who will benefit less than they are "hindered" by it, there are almost certainly vanishingly few.
Really interesting take, I've had the opposite experience. I've also seen very talented c++ devs screw things up in prod that rust doesn't even allow for. Really recommend taking it more seriously, it's fun once you get a handle on it. Also the tooling is really good now.
C++ has grown several language tools to let you write reliable, safe code.
... But it can't shed the old stuff without breaking backwards compatibility, and that's what bites you. The fact that smart pointers exist now doesn't stop a developer from passing around non -const char* with no size specifier and calling that a "buffer," and because the language is so old and accreted most of its safety features later, the shortest way to express an idea tends to be the likeliest way to be subtly wrong.
This is really just a problem that other languages don't have because they didn't have the same starting point.
The problem is that there is a lot of code and libraries using older patterns. And modern C++ is sufficiently different from the older C++ to constitute effectively a new language while still being unsafe. Moreover, in an attempt to address the efficiency the language has added views and ranges that provides more ways to corrupt memory. So why rewrite libraries in modern C++ when you can port them to Rust or Go and gain memory safety?
It's smelly if you have enough people on the team to know what new code versus old code smells like.
If your developers are coming to the table with some C++ tutorial books written a decade ago, good luck. Invest in a decent linter and opinionated format checker.
It's not easier to write "super complex stuff" in C++ than in Rust, precisely because C++ has much more cruft that the compiler can't check for you.
And so what if Rust is lowering the bar for entry to systems programming? I'd much rather fresh ideas and fresh blood enter the field, than it slowly dying as the only people with arcane C/C++ knowledge slowly retire/die.
That's a bold claim (since both languages are Turing complete). I presume you meant safe Rust? But that's kinda the point. If something is memory tricky it is supposed to go into unsafe so you can make a safe abstraction around it.
Unless you meant actually all of Rust. In that case, please share what's inexpressible in Rust.
No. I mean that there is a great deal C++ can capture and present in a library that cannot be expressed in Rust. Much of this will never be in Rust because of this or that early choice of direction.
At the most basic level, in Rust you cannot overload operators. You have no opportunity at all to code a move constructor. I could list off others all day long, but you probably would not understand most.
Then there are the things the borrow checker will not let you do, that would be correct, but it can't see that. You might say you can put those in "unsafe", but you can't really field a library where users sometimes must put a call in unsafe.
It is easy to insist you have never needed any of that stuff for your library, but that is really because you have constrained what you even think of trying to do by what you know you can do. We box ourselves in this way automatically, and it takes great effort to break out of such a mental box.
Well, that's partially true and partially false. Operators are syntax sugar for trait methods. Indeed, some operators can't be overloaded[1]. However, in that case, it's possible to make procedural macros that can handle such cases.
SQL builder programmers, for example, wanted assignment operator overload.
However, I'd argue that it's the wrong kind of overload to enable. The more code can do behind the scenes, the harder it is to reason about it, e.g. :
c = b;
Is this an assignment? Will it start the DB connection? In Rust, it can be just one thing. By sticking that code in proc macro and translating code, you signal your intent that something funny is happening here and that you should consult docs for more info:
sql!(a = b)
> It is easy to insist you have never needed any of that stuff for your library,
> Then there are the things the borrow checker will not let you do, that would be correct, but it can't see that.
Sure, but that's the Rice theorem at work (https://en.wikipedia.org/wiki/Rice%27s_theorem). Any non-trivial property of code is undecidable. That's why you have the unsafe escape hatch where you reason about why it's safe.
[1] which isn't that different C++ which prohibits some operator overload, but in C++ the list of operator not overloaded is small
> At the most basic level, in Rust you cannot overload operators.
I've heard this claim multiple places and I don't really understand it. Operators have corresponding traits that you can pretty easily define for your types.
My reading is that Rust doesn't allow overloading of constructors (don't exist as such) or assignments or whatever is actually needed for copying move constructors.
>At the most basic level, in Rust you cannot overload operators
I gave you a working example of operator overloading in Rust a while ago.
Why do you still state that Rust doesn't allow that? Is there a problem with the example?
I know a lot of different languages and have a feature matrix for reviewing them, and I would know if operator overloading didn't work since it's a row in there. It definitely does work in Rust (it's similar to Python's operator overloading).
When you say JavaScript, do you mean java? Rust undoubtedly raises the floor which is great, but designing scalable systems that enable new members to ramp up is a timeless skill independent of language.
As someone who isn’t a rust native but an interested outsider, it can obviously be cumbersome to use on my pet projects compared to something like python, js, c# or C. Dealing with references to generically types traits adds a lot of syntactical burden (re: shit for me to type) and defining types and their implementations leaves something to be desired regarding its grammars.
That being said, my toy programs do not require particularly complex types and the rust compiler is nothing short of a brilliant. The book is a surprisingly easy read, the module system is fine, cargo is decent out of the box, and there is an interesting mix of paradigms in the language itself. In my mind, the power of the compiler is certainly the big feature of rust and that compilers input language is decent enough such that I wouldn’t dislike using it as a daily driver.
In complex apps and services, Rust is generally faster than C++ because (especially over the long term, as there's churn in teams) C++ developers copy around stuff way more than necessary.
Yeah, made me reread the whole message with my sarcasm checker turned up. I can’t recall another widely used language of the era with as many foot-guns or one that went so long without a decent debugging experience.
It really draws into question the claim that “it's easier to write super complex stuff in C++ than in Rust” when so clearly incorrect about JS. Especially when we have _decades_ of evidence from world-stopping vulnerabilities in the C/C++ ecosystem.
With JS I meant it was something to run in a browser, nothing serious (initially). So from the historic perspective it was correct as for the reason why it existed. It was not meant to write multithreaded system services where most bad/average devs struggle (and it's not multithreaded to this day outside webworkers).
I describe it that way. Like everything else in life the path to success is short if you don’t get distracted by unnecessary conventions and a series of bad decisions.