Saturday, July 22, 2017

Down with NULL!

The introduction of null is arguably the biggest mistake in the history of computer science. Usage of null makes for sloppy code, cascading and often redundant null checks, buggy code due to missed null checks, and it makes for poor APIs.

Tony Hoare, the inventor of ALGOL W, calls it his billion-dollar mistake.

“I call it my billion-dollar mistake…At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.”.

Unfortunately, he wasn’t the only programming language inventor that couldn’t resist the temptation to put in a null reference. The inventors of Java, C# and many more fell into the same trap, causing years of pain and misery.

The designers of newer languages like Rust and Swift realized that that only way to eliminate the destructive side effects of null is by avoiding it altogether.

These languages use the optional feature instead of null.

The beauty of the optional feature is that only optional properties or methods can be null. If you try to set a non-optional property to null, you'll get compilation error.

That's an excellent language feature, because it allows to reliably exclude the possibility of null everywhere in the code, except for the parts that use optional, which should be the exception rather than the rule.

Swift is a great example. Instead of allowing every property (or method) to return nil, Swift forces you to explicitly declare that a property can be nil, otherwise, it assumes that the property is initialized.

So the below code will not compile, since the property ‘color’ is not initialized!

class Box {
   var color: String
}

You must do something like this:

class Box {
   var color: String = "Red"
}

Now, even if you never saw the implementation of Box, you know that you can safely use the property color without nil check..

// Create instance of class.
var example = Box()
if (example.color != nil) ... // NO NEED!

You can explicitly declare that a property or a method can be nil, by making it optional (adding ‘?’ post-fix after the type). However, especially for properties, that should be the exception rather than the rule.

class Box{
   var color: String = "Read"
   var colorOptional: String?
}

Now the caller knows that nil check is required. The caller doesn’t have direct access to the property, it has to unwrap it first using ‘!’

// Create Box instance.
var box = Box()

if (box.colorOptional == nil){
   print("It is nil")
}

box.colorOptional = "Blue"

if let c = box.colorOptional {
   print("Box has color \(c)")
   // The optional can be accessed with an exclamation mark.
   print(box.colorOptional!)
}

Languages like c++ and Java have added optional support via a community library, or directly to the standard library. It helps, it’s better than nothing, but it’s really too little too late.

Starting from Java SE 8 you can do this:

class Box {
    Optional<Integer> color;
}
Box box = new Box();
box.color.ifPresent(x -> System.out.println(x));

However, since Java’s type system allows null everywhere (If you try to set a non-optional property to null, the compiler wouldn’t mind), we can’t reliably exclude the possibility of null, and we still end up with null checks everywhere.

if (str != null && !str.equals("")) {
   // Do something with str
}

Unfortunately, in order to effectively combat the the terror of null, the optional feature must be backed into the language from the very beginning, and it must be enforced wholesale by the compiler.

No comments:

Post a Comment