The "fix" would be to not have arrays decay. I believe C++ could probably get there if it had taken Epochs, I further believe taking Epochs (P1881) when it was proposed would have been extremely disruptive but perhaps possible and worth attempting. I do not believe it's still possible, the moment passed and with it, in my view, any hope of salvaging C++.
Without Epochs, any and every such change to C++ is similarly disruptive and that's too expensive so more or less nothing gets fixed, instead layers of kludges must be added. That's how Foonathan ends up with: class foo final trivially_relocatable namespace() { … };
As for the billion dollar mistake, a null pointer reference results in a seg fault. But the array decay results in buffer overflows, the #1 problem in shipped C code, and the buffer overflows result in memory corruption. Memory corruption is much, much, much worse than a seg fault. For example, buffer overflows are exploitable by malware. Seg faults are not.
Hence, the array decay is the worst mistake.
> semantics
Accessing a[i] means i gets checked against the array length, and it's a fatal error if it doesn't.
> ABI
Same as struct {size_t length; void* ptr;}
> size
sizeof(a)
> length
__length(a) or something like that
We invent new languages almost daily and none of them have ever resolved the problem. I mean, when you start with a pointer, it's uninitialized. Setting it to null is much better than having it point somewhere, where there might be incorrectly interpreted data.
So, null. We have Java, suffering the same problem, Golang suffering the same problem and Rust, where you have the same problem if you call unwrap, without checking that all code paths ensure you have the value populated.
Seems to me this is an inherent problem of using an uninitialized value... so, what is the mistake?
The mistake is that Nothing isn't a kind of thing. It's a categorical mistake, enshrined in many programming languages because it was easy and they didn't realise it was a bad idea, that's what Tony's talk is about - he's the one who made the mistake originally.
> I mean, when you start with a pointer, it's uninitialized
You're talking about a language implementation detail. Indeed I'd say plainly, a language defect, particularly notable in C (and so C++) where it continues to cause problems.
> We have Java, suffering the same problem
That's correct, all non-primitive Java objects can be null instead.
> Golang suffering the same problem
That's correct, Go chooses "make representable states legal" rather than "make illegal states unrepresentable" and so every type must have a legal "zero" state.
> and Rust, where you have the same problem if you call unwrap,
Nope. Try it. Call "unwrap" on a Vec, or a HashMap, or a File. You can't, there is no such method, it's a method on Option.
> Seems to me this is an inherent problem of using an uninitialized value... so, what is the mistake?
Goodness no. An actual uninitialized value by default would be a design mistake. They're currently trying to fix this mistake for C++ 26. If for performance reasons you need to delay initialization you need a trick like Rust's MaybeUninit<T> wrapper. You certainly can't paper over it with null.