Technology

Swift: When to use guard vs if

Written by grcreativebox

One thing I’ve noticed recently in my code-base is that I tend to default to guard vs if. In fact, whenever I write an if statement, I facepalm myself and change it to a guard without thinking much.

But that’s become a problem. There is in fact a difference between guard and if and thought does need to be put into which one to use.

The difference is a bit subtle, but it is there. guard should be used when certain values are expected to be present for the function to execute as intended.

For example, in the try! Swift app, when it displays a presentation session type, the presentation title is the session title.

However, not every session has a presentation, so the presentation is optional. However, for this specific session type, it is expected that a presentation is in fact present and that it has a title. This is a perfect use-case for guard!

@objc public enum SessionType: Int 
    case workshop
    case meetup
    case breakfast
    case announcement
    case talk
    case lightningTalk
    case sponsoredDemo
    case coffeeBreak
    case lunch
    case officeHours
    case party


public class Session: Object {
    // this is optional because not all sessions have presentations
    // e.g. no presentation during breakfast
    open dynamic var presentation: Presentation?
    // other properties here

    /** The main name of this session */
    public var formattedTitle: String 
               
        switch self.type 
        case .talk, .lightningTalk:
            // for the talk / lighting talk session type
            // we expect the presentation to be there
            // if it's not there, it's a fail, so `guard` is used
            guard let presentation = presentation else  return defaultTitle 
            return presentation.localizedTitle
        // other cases continued...
        
    

The talk title should always be present for a presentation session type. If it’s not there, it’s a fail. This is why we use guard in this case.

However, consider another case. A Coffee Break session could be sponsored. In that case, the title of the coffee break should include the sponsor name. Both are correct – if there is a sponsor, we include the name of the sponsor, but if there isn’t one, we don’t include it. This is the type of case where if should be used:

public class Session: Object {

    /** A sponsor, if any, responsible for this session. */
    open dynamic var sponsor: Sponsor?

    /** The main name of this session */
    public var formattedTitle: String 
               
        switch self.type 
        case .coffeeBreak:
            // some sessions are sponsored, some aren't
            // it's not a fail if there is no sponsor
            // so `if` is used
            if let sponsor = sponsor 
                return "Coffee Break, by (sponsor.name)".localized()
            
            return "Coffee Break".localized()
        // other cases continued...
        
    

So as @ecerney puts it so well, think of guard as a lightweight Assert:

Like an if statement, guard executes statements based on a Boolean value of an expression. Unlike an if statement, guard statements only run if the conditions are not met. You can think of guard more like an Assert, but rather than crashing, you can gracefully exit.

So think if before you guard!

One thing I’ve noticed recently in my code-base is that I tend to default to guard vs if. In fact, whenever I write an if statement, I facepalm myself and change it to a guard without thinking much.

But that’s become a problem. There is in fact a difference between guard and if and thought does need to be put into which one to use.

The difference is a bit subtle, but it is there. guard should be used when certain values are expected to be present for the function to execute as intended.

For example, in the try! Swift app, when it displays a presentation session type, the presentation title is the session title.

However, not every session has a presentation, so the presentation is optional. However, for this specific session type, it is expected that a presentation is in fact present and that it has a title. This is a perfect use-case for guard!

@objc public enum SessionType: Int 
    case workshop
    case meetup
    case breakfast
    case announcement
    case talk
    case lightningTalk
    case sponsoredDemo
    case coffeeBreak
    case lunch
    case officeHours
    case party


public class Session: Object {
    // this is optional because not all sessions have presentations
    // e.g. no presentation during breakfast
    open dynamic var presentation: Presentation?
    // other properties here

    /** The main name of this session */
    public var formattedTitle: String 
               
        switch self.type 
        case .talk, .lightningTalk:
            // for the talk / lighting talk session type
            // we expect the presentation to be there
            // if it's not there, it's a fail, so `guard` is used
            guard let presentation = presentation else  return defaultTitle 
            return presentation.localizedTitle
        // other cases continued...
        
    

The talk title should always be present for a presentation session type. If it’s not there, it’s a fail. This is why we use guard in this case.

However, consider another case. A Coffee Break session could be sponsored. In that case, the title of the coffee break should include the sponsor name. Both are correct – if there is a sponsor, we include the name of the sponsor, but if there isn’t one, we don’t include it. This is the type of case where if should be used:

public class Session: Object {

    /** A sponsor, if any, responsible for this session. */
    open dynamic var sponsor: Sponsor?

    /** The main name of this session */
    public var formattedTitle: String 
               
        switch self.type 
        case .coffeeBreak:
            // some sessions are sponsored, some aren't
            // it's not a fail if there is no sponsor
            // so `if` is used
            if let sponsor = sponsor 
                return "Coffee Break, by (sponsor.name)".localized()
            
            return "Coffee Break".localized()
        // other cases continued...
        
    

So as @ecerney puts it so well, think of guard as a lightweight Assert:

Like an if statement, guard executes statements based on a Boolean value of an expression. Unlike an if statement, guard statements only run if the conditions are not met. You can think of guard more like an Assert, but rather than crashing, you can gracefully exit.

So think if before you guard!

About the author

grcreativebox

Leave a Comment