I kinda feel bad for taking this jab at C++, since it feels a bit below the belt... But that's kinda C++'s thing, isn't it?
You can either do the correct thing, or the succinct thing. There's hardly ever a satisfying compromise between the two either. Obviously, we want to do the correct thing most of the time, so that's why C++ ends up being full of ceremonious implementations in practice.
And alas, they're usually equally ceremonious to use, because abstractions in C++ are so incredibly leaky because of its poor type system.
I'm not sure why that is, but my gut tells me it's all this backwards [pseudo]compatibility.
That seems a fair observation to me, with the tweak that "correct" changes over time. C++ code can be written perfectly and still rot as the ecosystem changes, without changing the source.
We are really keen on preserving backwards compatibility, but break existing code anyway. We will not define a stable ABI, but also won't fix stdlib if it breaks ABI.
Also all code definitely has UB in it waiting for a compiler change to expose it as wrong and deserving of no longer working.
Ceremonious captures the state of the art accurately.
>C++ code can be written perfectly and still rot as the ecosystem changes, without changing the source.
But that's true of any system that depends on other systems with lax respect for contracts, or with no contract. You can depend on a third-party function get_time() that returns the seconds since the program started, and later on if its maintainers decide to change it to return a UNIX timestamp because they realized the wording was vague enough to allow it, any code that makes the wrong assumption will break.
C++ is, I would say, quite good as far as backwards compatibility goes. The problem IMO is that it's rather complex and some of its features have been misunderstood over time, such as the meaning of volatile or inline, and thus people have been writing subtly broken code that just happened to work when they originally wrote it.
Eh? There's the NVI comparison operator that fits that bill and maybe the std::forward_iterator one but the rest? Most of the other fixes was less code that's also simpler. Or are you getting thrown off by things like the enum slides where it's 3 different solutions all presented on a single slide?