Optionals – The Pyramid of Doom

If you’ve figured out how to deal with optionals using optional binding (check out my post on how to deal with them in a simpler way if you’re lost) you might have started wondering what would happen if you had to unwrap a really long list of optionals. Well, what happens is exactly what you think would happen, it becomes a giant pyramid of doom.

let optional1:String? = "optional1"
let optional2:String? = "optional2"
let optional3:String? = "optional3"

if let one = optional1 {
    if let two = optional2 {
        if let three = optional3 {
            print("\(one), \(two), and \(three) are unwrapped.")
        }
    }
}

Add more optional variables, and your pyramid just gets bigger.

How to avoid with guard

Swift came out with a keyword in Swift 2.0 called “guard” that works the exact opposite of “if let”. You can keep your unwrapped variable outside of a code block and avoid a cascade of curly braces. Assuming you’re using it inside a function, you can just return from the function if the optional is, in fact, nil. Otherwise you need to throw an error or somehow leave the current code block (scope) that your code is running in:

guard let one = optional1 else {
    return
}

guard let two = optional2 else {
    return
}

guard let three = optional3 else {
    return
}

I find guard a bit hard to work with since you have to have return or throw. It also took me a while to really grasp what was going on with it. If you’re like I was when I was first dealing with the pyramid of doom, it might help to have an alternative option.

Another option

No pun intended. Why not just check if they’re nil with if? It’s not against the rules. It just seems like most examples out there show the Swifty, Appley ways of handling optionals like guard, binding, chaining, and coalescing. They certainly are very appealing to the eye, and perhaps more efficient. But hey here’s another option that might help: check them all in a chain of “or” statements. All the variables need to be unwrapped anyway right? The code of interest is at the bottom of the pyramid, which means all variables need to be not nil for that code to run.:

if 
 optional1 == nil ||
 optional2 == nil ||
 optional3 == nil {
 //Do something to handle nil. Maybe put below code in "else". Idk.
}
 
let one = optional1!
let two = optional2!
let three = optional3!

print("\(one), \(two), and \(three) are unwrapped.")

It’s not perfect, but I think it’s more readable, understandable and usable for a beginner like I was (am). It also doesn’t take you to your doom. It’s similar to another solution called “early return”, but I think mine is a little different because it only uses one “if”.

Happy coding!

Leave a Reply

Your email address will not be published.