Avoid the billion-dollar mistake with Swift

First of all what is the billion-dollar mistake? Sir Charles Antony Richard Hoare invented the null reference in 1965 as part of the Algol W language. In 2009 Hoare describes his invention as a “billion-dollar mistake”.

Null reference is a useful construct, it is part of the Swift language, however it is an explicit part — represented by language type system.

Many other languages went half way. They have a type which signals that value might be a null reference. E.g. in C#

Person? p = new Person();

Person? is an optional type, it means that we should be careful with p. It might be a null reference. It also provides us with possibility to call methods without running into null pointer exception:

string s = p?.ToString();
int n = s.Length;

In case p is a null reference, the expression will not be evaluated further and the result will be a null reference. But we just deferred the problem. We get the null pointer exception on the second line. And this is what I mean by C# going only half way. s is of type string. C# does not prevent us from assigning null to a non optional type.

ObjectiveC deals with null reference in a slightly different fashion. In ObjectiveC all method calls are null safe:

Person *p = nil;
NSString *s = [p name];
int n = [s length];

In this case p is nil, s is nil and n is 0 (zero). No exceptions, no crashes every body happy?!

Not quite. nil (this is how null reference is called in ObjectiveC) has it’s own semantic. int is a primitive type. In ObjectiveC when calling methods on nil they will return default values for primitive types. So we say the name of a none existing person is of length zero. This is semantically incorrect. We just created “questionable” application state. Now have a look at this example:

if ([p hasProblems] == false) {/* do something important */}

A default value of a boolean is false. Our application logic is wrong and we don’t even get a null pointer exception to tell us about it.

Such bugs can be caught by unit tests, but wouldn’t it be better to not go full paranoia mode?

In Swift this will not compile:

let p : Person = nil

Also this will not compile:

let p : Person? = nil
let s = p.name

And this

let p: Person? = nil
let s = p?.name
let n = s?.characters.count

results in p, s, and n being assigned to nil, The type of n is Int? The name of a non existing person has no length, it is nil.

What about the boolean example?

if p?.hasProblem == false {/* do something important */}

Will not execute do something important. However if we introduce else branch. We introduce another bug.

if p?.hasProblem == false {
/* do something important */
} else {
/* resolve problems */

We will execute resolve problems, even though it is not our intention. This is due to the fact, that the result of p?.hasProblem is not of type Bool, but of type Bool?. There are two solutions for this problem:

  1. Introduce an if else branch
  2. Work with unpacked p

I would not recommend the first solution, because it just pollutes the code. Second solution looks like following:

func doSomethingImportantWithPerson(p : Person?){
guard let p = p else { return }
if p.hasProblem == false {
/* do something important */
} else {
/* resolve problems */

The guard let statement enables us to work with p of type Person from now on. If p is a null reference, we have to stop the application flow.

Here is another example of type unpacking

let p: Person? = nil
if let p = p,
let s = p.name,
let n = s.characters.count {
print("Name is of length \(n)")
} else {
print("Length of persons name could not be computed")

First of all it demonstrates that unpacking can be chained (this is also possible with guard let). But the main reason I wanted to show this option is because, here we do not have to stop the application flow. In this case the unpacked p is only valid for the inner scope of if statement. In case of guard let we unpack the value for current scope.

I started working with Swift since Swift 1. In the beginning I wrote some small libraries and a small App which was used by a few hundred people for couple of days. Back than, there was no if let and guard let concept in the Swift language. Last year I started working on an App which is used by many people every day. And you know what? I learned that if let and guard let are definitely my friends. I avoid using ? method call mostly and ! completely.

Crash and bug reports seems to agree with me