6 ms·
I really don't see how Rust has most of C++'s problems. Slow compiler, sure, though things are changing. Most complex languages in history? Only if you squint a
by Rusky 6y ago
I really don't see how Rust has most of C++'s problems. Slow compiler, sure, though things are changing. Most complex languages in history? Only if you squint at it from 10000 feet and ignore what the complexity is doing.
C++ has approximately eighteen different partially-overlapping categories of variable initialization, many of which are legacy-but-still-used! [0] And some of those categories have changed their boundaries every language version since C++11 (based on the definition of "aggregate").
C++ has three to five partially-overlapping kinds of type inference all in active use (auto, decltype(id), decltype((expr)), decltype(auto), template argument deduction)! This is interleaved with name lookup and overload resolution (below), so if some subexpression isn't compiling how you expect, you have a vast space of language features potentially to blame.
C++ has so many kinds of name lookup and namespacing that I'm not even sure how to count them. There's unqualified lookup, argument-dependent lookup, qualified lookup, class member access, etc. Sometimes you can't refer to things defined later (outside a class) and sometimes you can (inside a class). There is even undefined behavior if you mess up namespacing! (Undiagnosed ODR violations are every experienced C++ programmer's nightmare.)
C++ has ad-hoc overload resolution based on un-scoped identifiers, which even crosses namespace boundaries using one of the above name lookup modes. It has two kinds of user-defined implicit conversions ("explicit" and implicit) that also affect this selection process, on top of the zoo of "type promotions" inherited from C.
C++ classes have five to six kinds of "special member functions," some of which may be defined automatically by the compiler, each with its own rules for when and how, based on what else is defined in the class. These also contribute to overload resolution, of course.
[0]: https://blog.tartanllama.xyz/initialization-is-bonkers/ https://blog.tartanllama.xyz/initialization-is-bonkers/
Rust has a complexity of its own, but it's quite different in scale and quality. There is exactly one way to initialize a variable, exactly one kind of type inference, only two ways for names to be resolved (directly or via an imported trait). Overloading, implicit conversions (of which there is only one kind, Deref), and the replacement for "special member functions" (Copy, Clone, Drop) are all based on exactly one mechanism (again, traits).
The article has a pretty accurate description of how people experience Rust's remaining C++-like complexity, IMO: "I don't remember the order in which methods are resolved during autoderefencing, or how module visibility works, or how the type system determines if one impl might overlap another or be an orphan."
But one important aspect it leaves out (not being a C++ article) is that if you mess up any of these, you just get a compiler error- and Rust is well-known for having extremely helpful error messages. In C++ you may get a compiler error (known for being extremely unhelpful) or you may get undefined behavior.
Zig is certainly a smaller language than either C++ or Rust, but that comes at a cost. I would much rather hear discussion of those actual trade-offs than yet another "Rust is just as complicated as C++" non-claim.
- pron 6y agoYou're comparing 35-year-old C++ with 10-year-old Rust (and that doesn't even capture the story, because after two years C++ had something like 5x the market penetration Rust has after ten). But even now Rust, I think, together with C++, Ada, and Scala, easily ranks among the top five or so most complex programming languages in software history. It's definitely a matter of personal taste, but to me, Rust seems a monumental, awe-inspiring shrine erected to worship at the altar of accidental complexity. I admire the technical achievement -- I never imagined accidental complexity could be given such spectacular prominence -- but having spent my share of time with both C++ and Ada, I'd like to look elsewhere. I don't know if Zig will do the job, but the vision it has for low-level development is so refreshing, radical and different from everything else I've seen in my >20 years of professional software development that I'd like to give it a chance before settling for an improved C++. Anyway, it's a matter of personal aesthetic preference.
- Rusky 6y agoFour of the five pieces of accidental complexity I listed were present in C++98, so I'm not sure what the relative ages have to do with this. (You've also not mentioned any accidental complexity in Rust...) Instead, I attribute it to hindsight and differences in priorities- C++ today is still introducing new features with the same level of unforced complexity (e.g. compare C++ lambda capture clauses and coroutines, to Rust closures and async fn), while additions to Rust instead tend to "fill in" inconsistencies to remove edge cases and exceptions. I'm also not trying to convince you to drop Zig and settle for Rust! You can use either or both or neither, I don't mind! Rather, my point is that Rust's direction relative to C++ is the same one you praise Zig for- it provides the same control with drastically more economical application of fewer language features. Just because Zig goes further (again, at great cost to things like tooling, error checking, and messages) doesn't mean Rust didn't make a lot of progress.
- pron 6y agoSorry, I don't see it that way (and I don't entirely agree with your characterisation of what new Rust changes do, certainly not all of them). I think that both Rust and C++ are fundamentally built around a design concept that I find distasteful and wrong-headed for low-level programming -- https://news.ycombinator.com/item?id=24840818; https://news.ycombinator.com/item?id=24840818; I guess you can call it too much implicitness aimed to make the language appear something it isn't when printed on the page. Rust does it somewhat more elegantly than C++ and perhaps has other justifications for it (like sound guarantees) -- which is why I prefer it to C++, although not enough to justify a large investment until it has a significant market share -- but it espouses the same foundational design aesthetics. I think that whether people like or dislike Rust mostly has to do with whether they find that aesthetic appealing. I'm sure many people do and many people don't. BTW, I haven't "adopted" Zig that I would need to drop it for anything (it's not even 1.0 yet). I'm still with C++ for the time being. But I'm deeply impressed by Zig's revolutionary design and complete rethinking of low-level programming that I'm keeping a watchful and hopeful eye on it.