Proposal for types
Add the following type suffixes to the language: ? and !.
For every reference type (definition excludes slices, see below) T, the meaning of T! is “non-nullable T” and the meaning of T? is “nullable T”, and T without suffix means either T? or T! depending on context. For every non-reference type, T! is a synonym for T; there is T? added for an optional type with the same values as T plus a dedicated null value.
Naturally, T! converts to T? implicitly, but for T? to T!, an explicit cast is required and that cast is @system.
Multiple suffixes are allowed: T?! is T! and T!? is T?. That is, later ! or ? override any previous ones.
Every lexical use of a reference type without ? or ! appended is equivalent to one of them, depending on the module’s default. The module’s default is either specified (default null module m; or default !null module m;) or is the language’s default (which depends on the Edition).
In class member functions, this has ! type.
Any operation that requires a value of type T? to be non-null is a compile-time error.
Add operators for null-respecting access: ?., ?(…) (call if not null), ?[…] (index if not null), ?= (assign if null).
For if (auto x = expr) and if (T! x = expr) if expr is of type T?, x infers type T! and contrary to normal variable definitions, in an if or while condition, T? implicitly converts to T!.
To wrap the rest of the function in the then block of such an if statement, add if (auto x = expr) ... else … to the language. The ... is part of the core syntax and is intended to be read as “whatever follows next.” The else branch is mandatory, and its … means any statement or a possibly empty block. However, for an else block that would be { bool f = false; assert(f); }, add assert(auto x !is expr) to the language. (Note that assert(0) as special semantics and isn’t equivalent to a failed assertion.) Assert with declaration enforces non-null for a possibly null value.
No data flow analysis is proposed. Null checking is local and done by tracking ? and ! by the type system.
Proposal for ref
The most difficult one is ref. ref parameters and variables are assumed to be non-null, i.e. for ref x, &x should not be null. To allow for null references, add ref?.
Non-null enforcement of ref should be done even in the current edition to some degree. My bet is not a single D program ever correctly expected and handled a ref returning function returning a null reference. One would have to take the address of the result and test that pointer for null. No-one does that, except some people toying around with the edges of the language intentionally used ref with null.
In the current Edition, because T* is T*?, a dereferenced pointer is a possibly null reference. Binding one by ref would be an error. For this special case, I propose to allow it instead, as some programs would be full of errors (or deprecation warnings) otherwise.
Reference types
In this DIP Idea, reference types are:
- Pointer types
- Class / interface types
- Associative array types
- Function pointer types
- Delegate types
Slice types are not reference types in this logic because null slices are equivalent to an empty slices for the most part.
Permalink
Reply