On Friday, 26 July 2024 at 16:11:28 UTC, Walter Bright wrote:
>On 7/26/2024 3:21 AM, Richard (Rikki) Andrew Cattermole wrote:
>If the MMU is throwing an exception something has gone terribly wrong elsewhere and having a programming language force you to check for null is a reasonable precaution against this.
assert(p != null); // throws an unrecoverable exception
Array bounds errors also throw an unrecoverable exception
From what I've seen, the best argument against adding something to the type system to assist the programmer with handling null correctly where it may occur is that new, expensive analysis and possibly new control-flow statements are needed so that in cases where something nullable has been definitely ruled out of being null, the compiler won't complain anymore about the programmer failing to handle null.
The difference between an array index and a possibly null pointer is that almost all the time almost all the possible values for the array index are invalid, so it's quite obvious that out of bounds access must be accounted for, but also static analysis can't really make sure an index is in bounds. For null, however, it's a single value that's problematic. That a variable has a value different from one known iffy one is rather easy to express in a type system. What helps is that some core language constructs (new
) return non-null values, but as soon as the value is created, the type system forgets its non-nullness.
It's not about having defined semantics or undefined behavior, the semantics and behavior are defined. A type system that distinguishes nullable and non-nullable reference types helps programmers keeping track of when they have to handle null and when they don't, and whether a function expects null arguments or not. When all reference types can be null everywhere, but won't be in practice, it teaches programmers not to think of them. But the worst offender are ref
parameters. They can be null, too, (or *null
if you're pedantic), but practically no function taking a reference expects and handles the case where the reference is null — or even documents that assumption. Even seeing &var is null
probably looks to most like an obvious case of a vacuously false
expression. The reason why null references are allowed is because a reference can easily become null by accident in @safe
code, which means they need to have defined behavior. But that's only because pointers aren't distinguished if they can be null or not. Most references are initialized by obvious non-null expressions, only a pointer dereference is the an exception.