> The C++ committee, including Bjarne Stroustrup, needs to accept that the language cannot be improved without breaking changes.
The example in the article starts with "Wow, we have unordered maps now!"
Just adding things modern languages have is nice, but doesn't fix the big problems.
The basic problem is that you can't throw anything out. The mix of old and new stuff leads to obscure bugs. The new abstractions tend to leak raw pointers, so that old stuff can be called.
C++ is almost unique in having hiding ("abstraction") without safety. That's the big problem.
I find the unordered_map example rather amusing. C++’s unordered_map is, somewhat infamously, specified in an unwise way. One basically cannot implement it with a modern, high performance hash table for at least two reasons:
1. unordered_map requires some bizarre and not widely useful abilities that mostly preclude hash tables with probing:
2. unordered_map has fairly strict iteration and pointer invalidation rules that are largely incompatible with the implementations that turn out to be the fastest. See:
> References and pointers to either key or data stored in the container are only invalidated by erasing that element, even when the corresponding iterator is invalidated.
And, of course, this is C++, where (despite the best efforts of the “profiles” people), the only way to deal with lifetimes of things in containers is to write the rules in the standards and hope people notice. Rust, in contrast, encodes the rules in the type signatures of the methods, and misuse is deterministically caught by the compiler.
Like std::vector, std::unordered_map also doesn't do a good job on reservation, I've never been entirely sure what to make of that - did they not care? Or is there some subtle reason why what they're doing made sense on the 1980s computers where this was conceived?
For std::vector it apparently just didn't occur to C++ people to provide the correct API, Bjarne Stroustrup claims the only reason to use a reservation API is to prevent reference and iterator invalidation. -shrug-
[std::unordered_map was standardised this century, but, the thing standardised isn't something you'd design this century, it's the data structure you'd have been shown in an undergraduate Data Structures class 40 years ago.]
> For std::vector it apparently just didn't occur to C++ people to provide the correct API, Bjarne Stroustrup claims the only reason to use a reservation API is to prevent reference and iterator invalidation. -shrug-
Do you mean something like vector::reserve_at_least()? I suppose that, if you don’t care about performance, you might not need it.
FWIW, I find myself mostly using reserve in cases where I know what I intend to append and when I will be done appending to that vector forever afterwards.
I'm not familiar with vector::reserve_at_least but assuming that's an API which reserves capacity without destroying the amortized constant time of the exponential growth built in to the type, yes, that.
You absolutely can throw things out, and they have! Checked exceptions, `auto`, and breaking changes to operator== are the two I know of. There were also some minor breaking changes to comparison operators in C++20.
They absolutely could say "in C++26 vector::operator[] will be checked" and add an `.at_unsafe()` method.
They won't though because the whole standards committee still thinks that This Is Fine. In fact the number of "just get good" people in the committee has probably increased - everyone with any brains has run away to Rust (and maybe Zig).
It took me several reads to figure out that you probably meant ‘auto’ the storage class specifier. And now I’m wondering whether this was ever anything but a no-op in C++.
Every major project in that cares about perf and binary size would disable the option that compiler vendors would obviously provide, like -fno-exceptions.
Rust memory and type system offer stronger guarantees, leading to better optimization of bound checks, AFAIK.
There are more glaring issues to fix, like std::regex performance and so on.
"just get good" implies development processes that catch memory and safety bugs. Meaning what they are really saying between the lines is that the minimum cost of C++ development is really high.
Any C++ code without at least unit tests with 100% test coverage on with UB sanitizer etc, must be considered inherently defective and the developer should be flogged for his absurd levels of incompetence.
Then there is also the need for UB aware formal verification. You must define predicates/conditions under which your code is safe and all code paths that call this code must verifiably satisfy the predicates for all calls.
This means you're down to the statically verifiable subset of C++, which includes C++ that performs asserts at runtime, in case the condition cannot be verified at compile time.
How many C++ developers are trained in formal verification? As far as I am aware, they don't exist.
Any C++ developers reading this who haven't at least written unit tests with UB sanitizer for all of their production code should be ashamed of themselves. If this sounds harsh, remember that this is merely the logical conclusion of "just get good".
They were happy with C++ and it was the best thing since sliced bread.
They are now happy with rust and it is the best thing since sliced bread.
To me, languages have a, let's call it 'taste' for the lack of better word off the top of my head. It's that combining quality that pg called 'hacker's languages', such as C, and lisp, for example.
C++ feels like a bureaucratic monster with manual double bookkeeping, byzanthine, baroque, up to outright weird and contradictory in places. Ever since rust was conceived, I gave it multiple shots to learn. When I was not thrown off by what I perceive as java-style annotations, i.e., something orthogonal to the language itself where no one seems to have bothered to come to a consensus to be able to express this from the language itself, its general feel reminds me of something a C++ embracer will feel comfortable in. I.e., in pg's words, not a hacker's language, paired with a crusade of personal enlightenment. What used to be OO and GoF now is memory safety as-implemented-by-rust (note: not by borrow checker, we could've had this with cyclone, for example, more than two decades ago).
I have, in my original comment, marked this as my personal opinion and feeling, as is the above. I'm not arguing. I love FP and the idea of having a systems language with FP concepts working out to memory safety and higher level expression sounds like the holy grail of yester-me. I'm disappointed I couldn't find my professional salvation in rust with how uneasy I feel within the language. It's as if a suit and tie was forced on me, or a hawaii shirt and shorts (depending on your preference, image it's the thing you wouldn't voluntarily wear).
Now, if other folks also mirror my observation of how the folks flock from C++ to rust, you bet they take their mindset and pedestal with them to stand on and preach off of. At least those I know do, only their sermon changed from C++ to rust, the quality of their dogma remained constant.
Gotcha! I just didn't make the connection, when I read your comment I thought "what does a list of C++ features + the idea that people left it because they didn't like where it's going mean that the two languages are the same?"
I wasn't interested in arguing either, I was just trying to understand what you meant, and now I do. Thank you for sharing.
Rust was definitely created as an alternative to C++, but I don't really get your criticism. Unless you're just saying you don't like robust languages with very strong type systems or something?
To me, Rust feels as if it had sprung from the same mind. Or in the case of C++, set of minds. Who have a common mindset. I sadly don't critize rust's general design choices constructively. It's more of a public realization, '"C++ mind-set compatible" might just be the quality to describe the specific aroma I dislike in this melange".
I'm fine with robust languages with very strong type systems, I think. Are Haskell, ML, F#, Scala in this set? Robust and very strongly typed enough? I don't dislike their taste, even though I think I've had enough scala, specifically, for this life time. If these aren't in the set you're thinking of, I'd like to know what makes up that set for you.
The example in the article starts with "Wow, we have unordered maps now!" Just adding things modern languages have is nice, but doesn't fix the big problems. The basic problem is that you can't throw anything out. The mix of old and new stuff leads to obscure bugs. The new abstractions tend to leak raw pointers, so that old stuff can be called.
C++ is almost unique in having hiding ("abstraction") without safety. That's the big problem.