Swift 2.0's guard isn't just for throwing

Like many of the new Swift 2.0 features introduced at WWDC, guard is capable of supporting many useful patterns not all of them immediately obvious. The very verb "guard" makes us think about protection, but it can be much more broadly used than that. 

Let's think about a simple example. We want to get to work post WWDC so we want to have a set up a simple schedule with some reminders. What do we want to do? What else? Eat, Sleep, Code...

enum Activities {
    case Eat,Sleep,Code
}

Pretty straight-forward. We also want reminders (because when we are in the zone... we're in the zone)... So let's create a new value type for that. 

struct Reminder{
    let activity : Activities
    
    var numberOfReminders = 1
    
    func reminderText()->String{
        switch activity{
        case .Code:
            return "Code great things"
        case .Eat:
            return "Munch time"
        case .Sleep:
            return "Chill"
        }
    }
    
    func schedule(){
        print("Scheduled reminder to \(reminderText()) up to \(numberOfReminders) time(s)", appendNewline: true)
    }
}

It's quite simple. We can specify what the activity is, how many times we should be promoted to do it, and then a schedule function which for this example just echoes out the details of the reminder to the screen. 

OK, let's create a simple schedule

let schedule = [
    Activities.Eat,Activities.Sleep,Activities.Code,
    Activities.Eat,Activities.Sleep,Activities.Code
]

Looks about right, doesn't it? Now what we'd really like to do is schedule a reminder for everything apart from sleep (um... that's optional... right?). How might we do that? 

for activity in schedule{
    var reminder = Reminder(activity: activity, numberOfReminders: 1)
    
    if reminder.activity == .Eat{
        reminder.numberOfReminders = 2
    }
    
    if activity != .Sleep{
        reminder.schedule()
    }
}

OK... that's good, and this example it's not a problem... but what if we were going to be calling this 1000's of times a second and there were 1000's of schedule entries? We'll be creating lots of reminder instances that we don't use. 

Previously in Swift 1.x we could have turned to optionals...

for activity in schedule{
    var reminder : Reminder?
    
    
    if activity != .Sleep{
        reminder = Reminder(activity: activity, numberOfReminders: 1)
        
        
        if reminder!.activity == .Eat{
            reminder!.numberOfReminders = 2
        }

        reminder!.schedule()
    }
}

Yuk. Although I could have been a bit tidier... we begin to lose the clarity from our code with unwrapping (or I could have used optional calls... or I could have used let... but the point is the algorithm begins to get lost in the syntax). However we do it... if we change this function we are going to have to remember what our strategy for it was and keep doing it. For me, Swift is all about being able to be absolutely clear about our intent (be kind to future you), and this is loosing it. 

guard makes it easy to communicate precisely what our logic is....

for activity in schedule{
    guard activity != .Sleep else {continue}
    
    var reminder = Reminder(activity: activity, numberOfReminders: 1)
    
    if reminder.activity == .Eat{
        reminder.numberOfReminders = 2
    }
} 

Instead of returning or throwing as we might normally think about using guard, here we simply say "If the activity is sleeping, move on to the next schedule entry". The rest of the code can carry on. 

Combine this with our powerful friend defer, we can be very expressive (and to my mind, natural). What if we always want to add the activity to the calendar, but still only remind for Eating and Coding? Simple, again... defer isn't just for getting out of functions!

for activity in schedule{
    //Always add the activity to the calendar
    defer{
        print("Adding \(activity) to the calendar", appendNewline: true)
    }
    
    //Carry on if it's Sleep, no need for a reminder
    guard activity != .Sleep else {continue}
    
    var reminder = Reminder(activity: activity, numberOfReminders: 1)
    
    if reminder.activity == .Eat{
        reminder.numberOfReminders = 2
    }
    
    reminder.schedule()
}

Our output is exactly what we'd expect

Scheduled reminder to Munch time up to 2 time(s)
Adding Activities.Eat to the calendar
Adding Activities.Sleep to the calendar
Scheduled reminder to Code great things up to 1 time(s)
Adding Activities.Code to the calendar
Scheduled reminder to Munch time up to 2 time(s)
Adding Activities.Eat to the calendar
Adding Activities.Sleep to the calendar
Scheduled reminder to Code great things up to 1 time(s)
Adding Activities.Code to the calendar

Swift 2.0 really has picked up some incredibly rich semantics with the new language elements. I can't wait to use them, and future me can't wait to read them!