7 ms·
I have this impression that modern C++ is far more complex with a far more large surface area (from the perspective of learning the language) than Rust. Becaus
by wg0 3y ago
I have this impression that modern C++ is far more complex with a far more large surface area (from the perspective of learning the language) than Rust.
Because I am not expert in both, what folks that came from C++ to Rust or have to work regularly work with both say about that?
- Filligree 3y agoDramatically more so. Rust is complex, but most (not all!) of the complexity is there to support a specific, modern, safe style of programming. C++ adds fifty years of cruft to that. A lot can be said about the surrounding social environment, but as far as the languages go, I don't think it's far wrong to say that Rust is "C++: The good bits".
- ReactiveJelly 3y agoYeah I guess I'd phrase it as 3 kinds of "complexity" Rust is complex because the compiler has many ways to say "No I won't compile that, it might be wrong". C++ is complex because it requires the programmer to understand every feature used in the codebase. (e.g. Will the compiler warn me if I use inheritance and dynamic dispatch wrong? I'm not sure. I find code with inheritance hard to read.) Go _code_ is complex because the language is too simple. (if err != nil is waterbed complexity)
- Sohcahtoa82 3y ago> Rust is complex because the compiler has many ways to say "No I won't compile that, it might be wrong". Doesn't Rust have an escape hatch in the form of the "unsafe" keyword for cases where you're reasonably sure the code is safe and correct? I haven't used Rust and most of my knowledge of it comes from HN, so I could easily be wrong.
- Filligree 3y agoIt does, which is where the social aspect comes in: You're expected to make every reasonable effort not to use it, even if that comes at slight costs in performance, because practically speaking people are terrible at making those judgements. Sometimes works well. Sometimes, unfortunately, it leads to bullying.
- Sohcahtoa82 3y agoI always pictured that in a professional setting, engineering management would have an edict that `unsafe` is simply not allowed, or possibly, they allow it with extensive code review by multiple engineers. And that there would also be a lot of people trying to implement a double-linked list and finding themselves having to sprinkle "unsafe" all over the place to satisfy the borrow checker.
- Filligree 3y agoBoth of those happen. Though in practice, unless you’re specifically implementing basic infrastructure, I’ve never yet had any need to use unsafe.
- justincredible 3y ago[dead]
- marcosdumay 3y ago> C++ adds fifty years of cruft to that. If "that" refers to the support of a modern, safe style of program, then no, C++ has only the cruft, not that.
- dthul 3y agoI work with both, having started with C++ about 17 years ago, and agree that Rust feels like a relatively simple language compared to C++. Rust might feel harder to learn initially because the borrow checker won't let you compile certain programs, but once you are over this initial hump, the rest is quite straightforward.
- jbaber 3y agoI keep selling it as "Like vim, there's just this one thing to get over, then everything's clear." https://jbaber.sdf.org/misc/editors/learning_curves.jpg https://jbaber.sdf.org/misc/editors/learning_curves.jpg
- raverbashing 3y agoI guess it's safe to extend the analogy to "C++ is like Emacs" then
- fluoridation 3y agoI don't really agree with that. I'd say they're complex in different directions. C++ has complexities Rust doesn't because it bends over backwards for source-level compatibility. A lot of it is entirely at the semantic and pragmatic level. Rust's complexities are mostly due to its type system, meaning the complexity is at the syntactic level. I had never seen a computer crash because an IDE was trying to figure out how to parse a program before I worked with Rust, for example.
- foooorsyth 3y ago>I had never seen a computer crash because an IDE was trying to figure out how to parse a program before This happens daily on my Intel MBP in Xcode. In only a ~15k LoC small app, 99% Swift. I’ve had to break up several functions into smaller ones purely because the compiler chokes so easily. They actually have a dedicated error message to the tune of “couldn’t figure out types here, could you break this function up please?”. But yeah, outside of that I’ve never seen it happen in major languages using major language tooling. Never even saw it in 5 million+ line C/C++/.NET CLR mixed codebases.
- layer8 3y agoC++ precedes Rust by ~30 years. Just wait how large the Rust surface area might have become in 2053. There’s lessons to be learned from history, so hopefully less, but about every successful language so far has only kept growing and becoming more complex.
- hmfrh 3y agoSurely the C++ surface area will also have increased significantly in the same span of time which means that Rust will still be ahead?
- bluGill 3y agoProbably, but how much is an open question.
- AnimalMuppet 3y agoBy then, there may be a newer "new" language that is simpler than Rust.
- ReactiveJelly 3y agoIndeed it's already grown `async` and `?` since 1.0. But I love those features, they're a good thing. In Rust, the compiler still checks everything. I can't mis-use async or the question mark operator and accidentally make my code unsafe. In C++, I'm expected to know everything about every feature I use, so I have to be paranoid. Sure I remember that unique_ptr isn't atomic, do my juniors remember that? Sure, returning a reference to a local variable is a warning, but it's not an error, right? Many less-healthy teams probably ignore those warnings. And I myself don't even remember the rules for SFINAE or `move` in full. Not to mention that OpenCV's mix of shallow and deep copying for matrices casually breaks `const`. In Rust, more surface area is just more Lego bricks. If two Legos snap together, you're safe. If they don't, don't force them. C++ expects you to force everything and take responsibility for not being a human encyclopedia of the language.
- no_wizard 3y ago
- kitkat_new 3y agoThis. It always amuses me when people complain about complexity in Rust. It feels like they have no idea what they don't know about the alternatives
- gp 3y agoC++ lets you write anything you can imagine, and the language features and standard library often facilitate that. The committee espouses the view that they want to provide many "zero [runtime] cost," abstractions. Anybody can contribute to the language, although the committee process is often slow and can be political, each release the surface area and capability of the language gets larger. I believe Hazard Pointers are slated for C++26, and these will add a form "free later, but not quite garbage collection" to the language. There was a talk this year about using hazard pointers to implement a much faster std::shared_ptr. It's a language with incredible depth because so many different paradigms have been implemented in it, but also has many pitfalls for new and old users because there are many different ways of solving the same problem. I feel that in C++, more than any other language, you need to know the actual implementation under the hood to use it effectively. This means knowing not just what the language specifies, but can occaissionally require knowing what GCC or Clang generate on your particular hardware. Many garbage collected languages are written in or have parts of their implementations in C++. See JS (https://github.com/v8/v8)and https://github.com/v8/v8)and Java GC (https://github.com/openjdk/jdk/tree/36de19d4622e38b6c00644b0035521808574e255/src/hotspot/share/gc https://github.com/openjdk/jdk/tree/36de19d4622e38b6c00644b0...) I am not an expert on Java (or C++), so if someone knows better or can add more please correct me.
- pjmlp 3y agoThere are Java implementations in Java like Jikes RVM. Garbage collected languages can be easily bootstraped, it is a matter of what intrisics are available, and what mechanisms are availble beyond plain heap allocation. Oberon, Go, D, Nim, Modula-3, Cedar are some examples.
- gp 3y agoBut mainline Java is written in C and some C++, right?
- mauvia 3y agoHonestly, there's a "lot" of extra stuff but the standards committee has a general standard that things that can be done in a library don't need to be supported on the language level, meaning 90% of the new stuff is going to be invisible to you except in making the language more ergonomic to use. An easy example is ranged-for. It depends on so much complexity internally that the end-user basically will never see. All they'll see is that as long as std::begin and std::end are defined for a container you can just `for (auto item : container)` it. Stuff like overload resolution is essential to it but you don't need to know overload resolution rules to use ranged-for. Or the way initializer lists make initialization so much simpler. The way you can leave constructor writing to the compiler for so many different types of constructors. How the compiler handles elision so well because of how the constructors are designed. You don't need to write a single rvalue reference move constructor for simple types. They're generated for you. The current ongoing push to make large parts of the standard library constexpr so you can have seriously complex things going on directly at compile time to result in a minimal output that can just put in equivalent constants to constexpr function calls. Like, the reality is, it is pretty much a core principle of the language that you can write C++2003 if you really want to, and everything on top of it just makes writing things easier. But if you want to piecewise substitute your code with the latest stuff it more often than not becomes terser and more straightforward because of the evolution of the std library.
- benreesman 3y agoI’ve done a pretty fair amount of both, more C++ in total, more recent work in Rust. I think it really depends on whether you’ve got a mountain of legacy C++ with dated infrastructure and practices or a modern C++ code base at shop that runs a tight ship. In the former case the incidental as opposed to inherent complexity in C++ is a real PITA compared to Rust (which isn’t exactly shy about gratuitous complexity especially in the trait system and going more than a bit overboard with macros IMHO). C++03 written without modern tooling and a hardass style guide and stuff is usually a nightmare. I would vastly prefer to work in almost any Rust codebase compared to a sprawling nightmare of code that still calls new/delete routinely. A modern C++ codebase with all the best practices and tools and stuff? 6 one way half dozen the other more or less: Rust is now fast and feature full enough to be an option for most anything C++ would do. Do you like hardcore affine typing by default or dislike it? Another way to think about it is that modulo some big differences: Rust bundles (and mandates) a bunch of stuff you opt into in C++: a uniform set of best practices, hardcore static analysis, a credible strategy for catching memory safety issues and UB and thread safety issues. (The case is overstated about the difference in efficacy of e.g. ASAN and the borrow checker, they have pros and cons and it’s not a 1-bit debate). C++ tooling has a few important edges (though Rust is catching up): clangd is usually (always?) faster and more stable than rust-analyzer but you can throw hardware at it so it’s not a huge deal. Cargo is just a dunk below some project size. Above some project size the story is still evolving. It’s just not as big of a difference as you often hear one way or the other. I’d probably default to Rust unless I had library interop reasons to go C++ (which is often).
- pavon 3y agoThis might be influenced by the fact that I've used C/C++ for much longer, but my impression is that Rust is an even larger language with more details to learn than C++. The difference is that in Rust if you get the details wrong (in safe code) you get a compiler error or at worst a logic bug, while in C++ sometimes you get a compiler error and sometimes you get memory corruption or integer overflows, or undefined behavior. Expanding on this, the general concepts you need to understand for both are about the same, but because Rust enforces them in the compiler, you have to learn the detailed rules of how the language enforces ownership and lifetimes and such which is more detailed/complicated/restrictive than the concepts themselves. Furthermore, some of the Rust language details cause library APIs to become more involved than they would be in C++. An example in the std library is that in C++ handling errors and function results are orthogonal features. With sum types they are intertwined, and the Rust community is more liberal with adding convenience functions and syntax so you end up with a combinatorial explosion of all the different ways you want to handle the error combined with all the ways you want to handle the result, with about 40 methods each in Result and Option, plus methods for handling errors in iterators (functional streams). Lifetimes and async can also complicate crate APIs in ways that don't exist in C++. None of them are difficult on their own, but the shear volume of things you need to learn an remember makes me appreciate the minimal Go philosophy. On the flip side, the places where C++ gets more complex are all the little bad decisions that can't be fixed for backwards compatibility like the stupid numeric conversion rules inherited from C which can easily bite you. And both the C and C++ string/stream libraries suck in their own ways.
- trealira 3y ago> This might be influenced by the fact that I've used C/C++ for much longer, but my impression is that Rust is an even larger language with more details to learn than C++. The difference is that in Rust if you get the details wrong (in safe code) you get a compiler error or at worst a logic bug, while in C++ sometimes you get a compiler error and sometimes you get memory corruption or integer overflows, or undefined behavior. I disagree. Rust seems less complicated in many ways. For example, move semantics are a lot simpler; they're always a byte copy, whereas with C++, you have to remember rvalue references, lvalue references, and universal/forwarding references (which are usually rvalue references but sometimes are lvalue references). You also have to be careful not to mess with a moved-from object, as it's in an unspecified state. C++ also makes a distinction between trivially copyable types and non-trivially copyable types (a distinction Rust doesn't make). It's difficult to remember the rules for non-trivially copyable classes, but they boil down to "if it has a user-provided constructor, destructor, or copy-assignment operator; or if it has virtual functions; then it's not trivially copyable." In Rust, all you have to remember is that types are by default moveable (and moves are a memcpy), deep copies are implemented through the Clone trait, and if your type can't be memcpy'd (e.g., a self-referential struct) it needs to only be accessible through Pin pointers, which ensure that it isn't memcpy'd in safe code. Another thing: you can cause a use-after-free error by combining coroutines with lambdas [1]. An error like this only happens because C++'s rules around coroutines and lambdas are complicated enough that the committee didn't forsee this happening. This seems indicative of higher complexity in C++ than Rust, to me. [1]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95111#c23 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95111#c23
- amalcon 3y agoI've worked a lot with C++, and a small to moderate amount with Rust. I tend to prefer Rust when given the choice. Comparing the overall complexity levels is something of a category error, though. Most of the complexity of Rust is in the core functionality, idioms, and conventions of the language. You'll need to grapple with most of that complexity very early. Most of the complexity of C++ is in the various functionality that was either inherited from C or accumulated over the decades after that. Most individual pieces of software don't use all of that. E.g. approximately nothing will use both va_list and variadic templates (ok, maybe indirectly through libraries, but not in a way the direct author needs to think about). The latter is just a better way of accomplishing what the former does. There are lots of variations on this theme. My sense is that, in practice, Rust has a steeper learning curve than C++. I find it more productive now that I'm pretty familiar with it, so I think it's worth that steeper learning curve. I still think it's a bit steeper.
- armchairhacker 3y agoApples to oranges. Rust's borrow system is something you couldn't implement in C++, meanwhile C++ has far better allocator and compile-time support and probably more features in total (things like concepts, intrinsic bitfields, etc.). Importantly (afaik), Rust has far less features which are deprecated and/or in the specification but barely implemented.
- School-Cotton 3y agoI've used both professionally (Rust for the last 4 years) and I 100% agree. Rust, even with stuff like async, is a much, much, much simpler language than C++.
- lowbloodsugar 3y agoI’ve got over a decade in C++ and I won’t use it unless forced (I.e. paid more money than I can reasonably refuse). It’s only gotten worse and worse. I would and have used C before I’d use C++ and now I’d use Rust before either of them.
- alphanullmeric 3y agoThere are many, many, many things that are regular classroom exercises in C++ that are extremely difficult or impossible to do in rust. Rust programmers tend to just pretend like anything rust doesn’t do well is an antipattern. Making the simple case simpler and the complex case way more complex is not desirable for most people.
- kaba0 3y agoArguably, Rust is “just” a C++ subset with RAII made into a compile-time guaranteed primitive, and the only possible way to manage objects. Add to it that it is a new language that had the hindsight of C++’s warts, and no backwards compatibility on C and its own existing syntax, it would be very surprising to see Rust as more complex.