Three Kinds of Nothing

nil, Void & Never

swift develop

A gem from Advanced Swift objc.io (credited to David Smith on Twitter) is the appreciation of Swift’s three representations of nothing. Although the language's syntactic shortcuts give us succinct code they sometimes mask the details and in doing so blunt our understanding of how things work.

This post explores and contrasts the meaning of the three kinds of nothing: nil, Void and Never.

nil — The absence of a thing

Everyone is familiar with the value of nil, or more specifically Optional.none. It's the complement to Optional.some and the semantic analogue of C languages' NULL.

var aThing: Optional<Thing> = .none

Void — The Presence of nothing

The Standard Library describes the type Void as "the return type of functions that don’t explicitly specify a return type". So we might deduce that functions and methods either return something or they return the presence of nothing:

func f() -> String {
    print("Shall we play a game?")
    return "something"
}
func f() -> Void {
    print("Shall we play a game?")
    return Void()
}

Or equivalently:

func f() {
    print("Shall we play a game?")
}

Since Void is a type we can instantiate an instance of it.

var nothing: Void = f()

And we can also test its equality to show that all kinds of nothing are the same!

assert(nothing == Void())

The Standard Library actually defines Void as equivalent to the empty tuple; giving rise to another equivalent function declaration.

public typealias Void = ()
func f() -> () {    
    print("Shall we play a game?")
    return ()
}

But now things are strange. The empty tuple expression () is both the type and the value of nothing.

var nothing: () = ()

Never — The thing which cannot be

Never is a type that has no valid values and cannot be instantiated.

Consider this enum type with no cases.

public enum Never { 
}

Such types are termed uninhabited. The set of all possible instances of Never is empty.

This leads us to a situation where we can declare a variable of the type but have no values with which to initialise it.

var never: Never = ???

OK, perhaps we can declare a function that returns type Never and assign that?

func f() -> Never {
    print("Shall we play a game?")
    // return ???
}

But how can a function return a value of a type that cannot be instantiated?

Swift gives the compilation error Function with uninhabited return type 'Never' is missing call to another never-returning function on all paths for this declaration. To silence the error the function must call another function that returns Never like e.g. fatalError.

Never tells the compiler that the function will not return. This contradicts the previous idea that "functions and methods either return something or nothing". In fact, sometimes they don't return at all!

func f() -> Never {
    fatalError("The only winning move is not to play")

    // Execution does not continue.
}

And now we can compile code that initialises a value of type Never.

var never: Never = f()

Of course this initialisation is guaranteed to never run.


[Photo by Thierry Meier on Unsplash]

Next Post