Update, 07 Feb 2017
As of Swift 3, some of the code below may not work properly anymore. To see what changed, read Pyramid of Doom Updated (Swift 3).

Original Post

Today we continue the topic of avoiding Swift’s Pyramid of Doom that we started in previous post, on `guard` statement.
This time, we cover a feature from Swift 1.2 – it’s not a new thing, but still very handy and useful to have in your arsenal.

Every now and then I see older code that does something like this:

``````func pyramidOfDoom(x: Int?, y: Int?, z: Int?) {
if let x = x {
if let y = y {
if let z = z {
//do something with x, y and z
print("\(x, y, z)")
}
}
}
}
``````

It works and was necessary in Swift 1.0 (unless you added your own workaround for it).

In Swift 1.2, `if let` allows unwrapping multiple optionals, which lets us rewrite previous example into

``````func noPyramid(x: Int?, y: Int?, z: Int?) {
if let x = x, y = y, z = z {
//do something with x, y and z
print("\(x, y, z)")
}
}
``````

So much better!

What’s also useful and helpful for keeping your code clean, is the ability to add `where` clause to your optional binding.
It lets you check not only if optionals hold any value, but also if that value meets certain condition.

Let’s take a look at code we would write normally, using `if` statement

``````func ifStatement(x: Int?, y: Int?, z: Int?) {
if let x = x, y = y, z = z {
if (z < 4) {
//do something with x, y and z
print("\(x, y, z)")
}
}
}
``````

Assuming we need `z` to be less than `4` - code seems pretty normal. Let’s rewrite it to use `where` clause

``````func whereClause(x: Int?, y: Int?, z: Int?) {
if let x = x, y = y, z = z where z < 4 {
//do something with x, y and z
print("\(x, y, z)")
}
}
``````

One less level of code indentation and a bit cleaner code. You can add one where clause per each `let` statement

``````func multipleWhereClause(x: Int?, y: Int?, z: Int?) {
if let x = x where x < 2,
let y = y where y < 3,
let z = z where z < 4 {
//do something with x, y and z
print("\(x, y, z)")
}
}
``````

which acts exactly the same as

``````func multipleWhereClause2(x: Int?, y: Int?, z: Int?) {
if let x = x, y = y, z = z where x < 2 && y < 3 && z < 4 {
//do something with x, y and z
print("\(x, y, z)")
}
}
``````

Which version to use? It’s mostly a matter of preference and depends what you think is easier to read.

I prefer version #1, as it’s a bit more explicit and for the same reason I advise you do the same – if you can add more readability by spending few more seconds on typing additional `let` statements – do so, people reading your code later will be grateful.

One important note to remember, is that assignment and unwrapping happens before the condition in `where` clause is checked.
This means, if your condition is unrelated to unwrapped variables – it might be better to check the condition first. Why?

``````func expensiveFunction(startWith: Int) -> Int? {
//despite what you see here
//it is really expensive to call this function!
return startWith * 2
}

func isTodayThursday() -> Bool {
//I'm writing it on Tuesday, so we can optimize ;)
return false
}

func expensiveUnwrapping() {
if let x = expensiveFunction(2), y = expensiveFunction(5) where isTodayThursday() {
print("\(x, y)")
}
}
``````

It matters how do we get our optional values. If, as in the example above, they come from a function that is really expensive to call – it would be smart to call it only if we can be sure that returned value will actually be used.

In the example above, our expensive function is being called twice, even though we don’t even get to use `x` and `y` variables.

For similar cases, you might use the fact that we are allowed to use one logic statement (outside of `where` clause) as long as it’s the first clause in the `if let` statement

``````func unexpensiveUnwrapping() {
if isTodayThursday(), let x = expensiveFunction(2), y = expensiveFunction(5) {
print("\(x, y)")
}
}
``````

This way our expensive functions will be called only if our initial logic clause is `true` (according to answer by Chris Lattner on google groups).

Adding one logic clause at the beginning, works exactly the same with `guard` statement

``````func guardUnexpensive() {
guard isTodayThursday(), let x = expensiveFunction(2), y = expensiveFunction(5) else {
return
}
print("\(x, y)")
}
``````

That’s it for now. In one of the next articles I will go into pattern matching and I’ll explain why following statements produce exactly same results. Stay tuned!

``````if let x = x {
printSomething()
}

if case let x? = x {
printSomething()
}

if case .Some(let x) = x {
printSomething()
}
``````