I think there's more to it (changing the language) than you are crediting it.
First, you don't have to use the new features (though eventually you'll be reading the code of people who did, so this is only half-valuable). There is new c++11 code being written every day -- in volume (a hard to pin down amount) it's sadly more than 50%. The usage surveys don't really capture this clearly (and it's not clear they could).
Second: often new features are for library writers, or are out there for library writers to use (e.g. coroutines, which probably will not be appropriate for many users before c++23, but pretty much need to be available for people to experiment with).
Third: the new features tend to be additive. For example you don't need to use many of the stuff in <algoritm> -- stick to a for loop unless you want to take advantage of some new capability (e.g. policies, which are't ubiquitous). Concepts are the same way: they will improve error messages and reduce bugs, but if you don't use them your code will in 99.9% work just fine. When you see a very simple example that uses concepts, it's not surprising that the concepts don't really improve a simple add function -- the case is deliberately simple for explanatory purposes.
Languages move forward. Even go recently caved and added in generics.
I think you hit it on head, that most new features are for library writers who need to capture every edge case succinctly. As someone who has used c++98 and only a little c++11, for nearly 15 years, and writes no libraries; I've had little real need for any new features.
The less you use the new features, the less benefit you get from them. You could stick to K&R C and get no benefit at all, but that would be equally as foolish as what you are doing.
The new features are there to improve your experience, and to make your code more reliable. When you have a choice between old and new, new is usually better.
Sticking to K&R, you would have as many bugs and crashes as other K&R code. Sticking to modern C++ makes most of such bugs impossible. That is progress.
You can stop learning and take up complaining at any time, as you have done.
But you can also start learning again at any time. Now is always a good time for that.
You don’t know what domain the person you are answering works in, so you cannot make such sweeping statements. Implying someone is foolish is plain rude. https://news.ycombinator.com/newsguidelines.html
But it complicates the compiler, complicates the tools, complicates the error messages,...
Take something as "simple" as operator overloading. If a beginner does a "5"+5, the compiler is forced to respond with "no operator + for the types given, types are: int, std::string" instead of the infinitely more friendly "can't add string to int". I actually _like_ operator overloading, I wish more languages stopped the silly practice of making language-provided primitives somehow
sacred and closed-to-extension. But look at how even this relatively straightforward and useful feature ruined the error message.
Part of this particular example is bad error message design. I mean, what are the chances somebody intended to do operator overloading but then forgot to implement the method? It would have been much better to say "Can't add string to int, Did you forget to implement operator+(.. .,...)?". This centers the common case first, then reminds the experienced about what could have happened in their case. But even this might confuse beginner and convince them that "5"+5 is somehow a reasonable thing to say (because it actually is in some contexts) that they just need to get that fabled operator+ from somewhere to make it work, instead of just outright telling them " nonsense, not gonna work".
Extensions are always, inherently, abstractly, a tradeoff. Because even if you are a perfectly spherical coder who doesn't interact with other code in any way, you at least interact with the language tools. And the tools _must_ know all the of the language: instead of just having the luxury to say "sorry mate can't do that" when encountering "5"+5, the editor/IDE/compiler has to spend the cycles to see if it _can_ do that, then report a message that simultaneously says that you can but can't.
As the features accumulate and interact, the tradeoff curve increasingly inflect against adding new things.
All of this in the abstract is a fairly balanced argument that applies to any language, the particular case of C++ is much, much worse. C++ have this aweful way of "retconning" new features. I can never put my hands on it, but C# creators practically design a new superset every major version and call it the same name without ever making people angry or afraid that the language is spiraling out of control, but every C++ feature gives me this dark feeling of "is this never ever going to end? how far are you willing to take it?".
Part of that is undoubtedly the syntax, remind me again what language class (regular, context free,..) is C++ syntax? The other day I was fooling around and thought of adding discriminated unions to C++, just a thin syntax layer over a more verbose idiom. The very first thing is to parse the damn thing, but that way lies madness. Because C++ have no agreed-upon, guaranteed formal grammar. There is a grammar online but it's gargantuan and was written by one man, there is a grammar in the standard but it's gargantuan and the standard says it's there for illustration only, there is a grammar (implicitly) in the source code of any working parser but it's gargantuan and full of hacks. So for all practical intents and purposes, C++ has no formal grammar. Think about that for a minute, a formal language that has no formal grammar. It's the bare minimum any formal language can have, and yet you can't do it safely because of the massive, beast-like bloat that is that language.
> Take something as "simple" as operator overloading. If a beginner does a "5"+5, the compiler is forced to respond with "no operator + for the types given, types are: int, std::string" instead of the infinitely more friendly "can't add string to int".
You are not allowed to overload operators involving only built-in types so operator overloading changes nothing about the expression "5"+5. Even if you could overload operator+ here, there is nothing preventing a compiler from giving you the friendly explanation if that operator does not exist (perhaps with an additional hint that it could be defined).
(Also, the expression "5"+5 is valid C++ but Clang has -Wstring-plus-int to warn you that it might not do what you expect.)
It’s true that C++ is huge but the complaint should be about the lack of epochs that would let us simplify the language instead of about very useful new features such as concepts, modules, or constexpr. If you’re already programming in C++ and you can’t take a few days every 3 years to learn about new additions, you’ll have even more problems with other languages.
> but the complaint should be about the lack of epochs
Rather than something as coarse as epochs, C++ includes a lot of fine grained feature test preprocessor definitions such as (to pick one at random) '__cpp_lib_constexpr_algorithms'.
It's harder to make this work with breaking API changes of course. I assume non-preprocessor versions that work with modules will be available in C++23...and perhaps they will support API changes?
Epochs would be more usable. Nobody can afford to litter their code with hundreds of feature tests.
API changes that change semantics are forbidden in Standard interfaces, although APIs can be extended, backward-compatibly. To make an actual change, we need to introduce a new name. Thus, when we get around to modernizing std::vector, the fixed version will have a different name, maybe std::vec, but conceivably std2::vector.
I don't know of any plans for feature test macro analogs that would integrate with modules.
To be usable, epochs would have to apply locally to a file, not to anything #included into that file, nor to any file #including it. And, it should be possible to tie them to modules, to say "you can use this module only from code in epoch C++XX or later".
> Thus, when we get around to modernizing std::vector, the fixed version will have a different name, maybe std::vec, but conceivably std2::vector.
Let us hope that if such a name transition ever happens that the hideous plague of multi-case identifiers does not infect the standard. Leave that to (a subset of) user code.
Either std26::vector or std::vec would work for me. `std26::vec` would probably be better because of possible confusion (as to which vector implementation is desired) due to use of `using` directives.
no, people were writing "concept-like" code since C++98 in a very bloated way with e.g. sfinae, this is just standardizing existing practice (while improving it of course)
Concepts have existed informally since the original C++ STL. For the last 25 years people have been trying to make them a language construct. The current design is the one compromise people could agree on while being implementable and backward compatible.
I haven't used it much yet, but I would still say it is pretty good although far from a proper template type system.
He got tired because of the insane complexity of the language, and in the video I linked he supports his complaint with extensive and damning examples.
His difficulties are characteristic of someone not seeking solutions to actual daily engineering problems, and instead getting lost in a maze of language lawyering.
If you approach features in terms of how they can be useful when coding, almost all of his difficulties never arise, or are easily sidestepped. For working coders that becomes second nature.
First, you don't have to use the new features (though eventually you'll be reading the code of people who did, so this is only half-valuable). There is new c++11 code being written every day -- in volume (a hard to pin down amount) it's sadly more than 50%. The usage surveys don't really capture this clearly (and it's not clear they could).
Second: often new features are for library writers, or are out there for library writers to use (e.g. coroutines, which probably will not be appropriate for many users before c++23, but pretty much need to be available for people to experiment with).
Third: the new features tend to be additive. For example you don't need to use many of the stuff in <algoritm> -- stick to a for loop unless you want to take advantage of some new capability (e.g. policies, which are't ubiquitous). Concepts are the same way: they will improve error messages and reduce bugs, but if you don't use them your code will in 99.9% work just fine. When you see a very simple example that uses concepts, it's not surprising that the concepts don't really improve a simple add function -- the case is deliberately simple for explanatory purposes.
Languages move forward. Even go recently caved and added in generics.