Optional - Functional

I have just read the chapter 5 of the book “Functional programming in Swift”. This chapter is about “Optionals”. And there are some interesting things I want to share.

First of all, one of the most frustrating problem that developers have been experiencing is working with nil (or null). Intuitively, nil (or null) implicitly means “failure”. For instance, you look up in a dictionary but cannot find it, then you got nil:

let mutualFriends= [
    "Anna": 137,
    "Chris": 222,
    "Dan": 80,
    "Fred": 152]   // mutualFriends: <String, Int?>
let x = mutualFriends["John"]      // x = nil

As usual, we want to assign x a default value instead of nil. We can customize it in this way:

var x: Int = defaultValue
if let y= mutualFriends["John"] {
    x = y
}

In fact, Swift supports an operator ?? to make this sort of declaration more concise:

let x = mutualFriends["John"] ?? defaultValue

This means: If the left of ?? is nil, then return the value of the right. Let’s dive a little bit into the operator ??. Roughly speaking it can be defined as follows:

// Custom ?? function
func ??<T>(optional: T?, defaultValue: T) -> T {
    if let x = optional {
        return x
    } else {
        return defaultValue
    }
}

This function works perfectly despite one problem: defaultValue is always computed even if the optional is not nil. Generally, the reason is that it is computed before passing in the function parameters. What we desire is that the computation of the defaultValue is only executed inside the else branch.

We can resolve it by passing “HOW” defaultValue is computed instead of the value computed already. Intuitively, it reminds us of using a function as a parameter. And see what it leads to:

// Custom ?? function
func ??<T>(optional: T?, computeDefaultValue: () -> T) -> T {
    if let x = optional {
        return x
    } else {
        return computeDefaultValue()
}

Come back to our example, we can use the operator ?? like this:

let x = mutualFriends["John"] ?? { myDefaultValue }

A little ugly with the closure, right? Fortunately, Swift does support “autoclosure type attribute” to deal with with. Let’s look at the official function of ??:

// Swift 1.2 ?? function
func ??<T>(optional: T?, @autoclosure defaultValue: () -> T) -> T {
    ......
}
let x = mutualFriends["John"] ?? myDefaultValue

Now, with the @autoclosure annotation, Swift is smart enough to map myDefaultValue to a corresponding function. Everything seems quite natural so far.