Use explicit nullable types

Put null into the type system where it belongs, and reap the benefits.

Several years of Hack and Flow projects have convinced me that explicit nullable types are the correct design for a language with null.

That is, the language treats (for example) string and ?string as two different types, making it a compile-time error to dereference a ?string before checking for null. Goodbye, null reference exceptions.

The best implementations of this do type refinement, where the type checker will locally upgrade a ?T to a T inside of a null check, using static analysis to prove, where it can, that the value is locally non-null. For example, in Hack:

$thing = maybeAString(); // $thing is ?string
if ($thing is nonnull) {
  doSomethingWith($string); // $thing is string
}

Once you’ve experienced this feature, you will consider it insane that you ever lived without it. It stands to reason: null is not a T; it’s the absence of a T! Why should you be allowed to treat it as a T? All of your new code in statically-typed languages should be making use of this to the extent your language allows.

For functional programmers

In languages like Rust, Elm, Haskell, OCaml, Mint, or anything else with algebraic data types and pattern matching, you don’t have to worry about this; your “null” is already part of your type system in the form of a Maybe monad or something like it. Broadly speaking, you don’t get null reference crashes in these languages.