On Wednesday, 16 April 2025 at 21:12:08 UTC, Walter Bright wrote:
> On 4/16/2025 12:57 PM, Dave P. wrote:
> You put a #pragma clang assume_nonnull begin
at the top of your C/C++/Objective-C code and you have to annotate only the nullable pointers. Most pointers in a program should be non-null and the nullable ones should be the exception that you have to annotate.
Annotation means more than one pointer type.
Back in the old MSDOS days, there were 5 pointer types - near, far, stack, code and huge. Dealing with that is a gigantic mess - which pointer type does strlen() take? Or worse, strcpy()?
Microsoft's Managed C++ has two pointer types with different syntax, a GC pointer and a non-GC pointer. The same problem - what pointer type does strcpy() accept?
It's an ugly mess, and why I've avoided any such thing in D.
I'm curious - how does one traverse a binary tree with non-null pointers? How does one create a circular data structure with non-null pointers?
There are three annotations: _Nullable
, _Nonnull
and _Null_unspecified
. _Null_unspecified
can freely convert between the other two types. If you don’t annotate a pointer (and don’t change the default), then it is a _Null_unspecified
for compatibility with existing code. strlen
and company thus take _Null_unspecified
. They should take _Nonnull
, but it’s old code.
For data structures, you mostly use _Null_unspecified
as the nullability is not as simple as this pointer may be null or not, it is a potentially dynamic invariant of your data structure. In D, you would annotate it as an @system
variable so only trusted code can modify it.
Where the annotations are really valuable is for function arguments and return. Can this argument be null or not? Now the compiler can help you instead of you having to memorize the documentation of every function you call.
I’ve consistently applied these annotations to my C projects and it works wonders. Many classes of mistakes are caught at compile time. Somethings are a dynamic property of your system, and for that there is a nullability sanitizer that can detect at runtime if a _Nonnull
pointer gets a null value (usually from a data structure that was not properly initialized).