The guard statement has been implemented in Swift 2.0. Since then there are quite a lot rumors about its usage. guard is not a general-purpose mechanism and this blog post wants to clarify some of these to help you understand WHEN and WHEN NOT to use this statement. It also explains differences between guard and a generally purpose if-statement.

The basics of guard

First of all let's clarify why guard was invented. Let's take a look at the form of a guard statement.

guard condition else {  
    statements
}

To be honest it strongly looks like "if-else-statement" version without the if part. Perhaps that's the reason for a mostly common misunderstanding that guard is only a reverse version of an if-statement. That would make guard quite useless because we could just negate the condition with our classic if-statement. So why did Apple invented guard?

According to Apple's documentation:

A guard statement is used to transfer program control out of a scope if one or more conditions aren’t met.

To sum up their main intention in two words: EARLY EXIT

Why using guard?

What are the advantages of an early exit when coding swift? Why inventing a new statement for that purpose?

Readability of the code

A typical flow with an if-statement would look like these:

if let username = usernameField.text, username != "" {  
    if let email = emailField.text, email != "" {
        if let password = passwordField.text, password != "" {
            // do awesome stuff here
        }
    }
}

// error handling here ...

This happens when we chain optional unwrapping. There are functional alternatives to handle this problem but they also increase the complexity of your code.
So you have to scroll to the end to see what happens when you leave the happy-path and your conditions aren't met. It gets worse with every condition you are adding to the code.

guard helps to avoid this by early exiting when an optional unwrapping fails. This keeps your code readable and easier to maintain:

guard let username = usernameField.text else {  
  throw SignupError.NoUsername
}
guard let email = emailField.text else {  
  throw SignupError.NoEmail
}
guard let password = passwordField.text else {  
  throw SignupError.NoPassword
}

print("username: \username, "email: \email, password: \password")  

Reduce force unwraps

On successful unwrapping guard automatically passes the condition to the scope where guard was called. You don't need to force unwrap previously checked conditions. You can see it in the previous code example. The print function in the last line uses the variables initiated with let in the guard condition part. guard automatically passes them to the scope.

There are tons of blog posts and articles that tell you to always prevent force unwrapping if possible! It may lead to unpredictable runtime errors and memory leaks. With guard you don't need to force unwrap your checked conditions.

Common code-smells

guard shouldn't be seen as a general purpose statement. It's usage is very situational and I'd like to talk about some guard code-smells in terms of clean code.

Excessive usage of guard

guard isn't meant to replace every reversed if-statement. Sometimes you simply don't benefit of an early exit. Especially when you have simple function that only contain a single if-else-statement. In terms of clean code it's much easier to read and understand what the code does when you split it into this single if-else block.

Don't use guard as a mechanism for optional unwrapping. Remember that guard was made for easier program control by using early exit! When it's just about unwrapping, it's better to use plain old if-statement.

Complex code in else-clause

Remember that the main aspect of guard is the early-exit to transfer program control out of scope. When your else clause looks like this, something's going wrong!

guard let doFoo = doFooProducer.doFoo else {  
  let productId = randomProducer()
  if productId == 3 {
     produceCar()
  } else {
     produceTree()
  }
   return
}

Don't put code complexity into your else clause of a guard-statement. You should simply check pre-conditions and not run complex error handling in the else-cause. This should be handled out of scope, i.e. by throwing exceptions.

It's fine to do some logging and anything else that helps you to get out of the function in a clean state. But when you write complex code in there, you're misusing the guard statement.

fin

guard is a powerful but very situational statement that helps you to write easier and cleaner code. It can keep your functions flat by preventing the pyramid of doom and provide an early-exit when you leave the happy path.

I pushed the XCode-Playground project with all code samples to github. You can clone it from here:
https://github.com/thecael/swift-guard-playground