If vs Guard – a Beginner’s approach

1. Introduction

Computer programming is about solving problems and getting things done the right way. However, as a beginner, you don’t care how you do it as long as you get it done. It works so why bother tackling it in a completely different way after all?

I thought the same way when I first stumbled upon the guard statement in Swift because it behaves like an if statement. So I approached it reluctantly at first and soon asked myself how I lived without it.

The biggest challenge you face when discovering new programming paradigms is changing the way you think. This can be scary at first because you are used to doing things in a certain way and now you suddenly feel overwhelmed. It takes time and patience to get used to anything new but it’s worth doing it in the long run – being able to choose the right technique for a certain problem is a skill that any software developer should have in his toolbox.

OK, enough talking – let’s see what the guard statement is all about.

2. The challenge

Your task for this tutorial is an easy one: determine the name of the day of the week for a certain day of the year. Before diving into coding, think how you would solve the problem and break it into steps. This is how I would do it:

  • generate a random day of the year;
  • determine the day of the week;
  • unwrap its value if it’s valid;
  • determine the day’s name based on the value;
  • print the name of the day to the console;

That’s it for the algorithm – now let’s move on to the implementation.

3. The forced unwrapping implementation

Fire up Xcode and open a playground. Delete everything from it and add this line to kick things off:

import Darwin

This imports the Darwin module into the playground – you use it to generate random numbers.

Note: This tutorial is not about the evolution theory – sorry for the disappointed fans out there. 🙂

Next generate a random day of the year:

let dayYear = Int(arc4random_uniform(365))

The arc4random_uniform function creates a random whole number between 0 and 364 since a year has 365 days.

Challenge: Generate a random day of a leap year.

Hint: Think of how many days are in a leap year compared to a regular one.

Solution:

let daylYear = Int(arc4random_uniform(366))

Now create an enumeration with the days of the week:

enum Days: Int {

  case monday, tuesday, wednesday, thursday, friday, saturday, sunday

}

The enumeration’s type is Int so the days of the week have raw values between 0 for Monday and 6 for Sunday.

Note: The first day of the week is Monday where I come from – if you live in the English speaking world feel free to start with Sunday instead. 🙂

Note: You can also declare the enumeration like this – the initial approach is shorter though:

enum Days: Int {

  case monday
  case tuesday
  case wednesday
  case thursday
  case friday
  case saturday
  case sunday

}

Next create the day’s name variable – it’s variable because you are going to change its value soon:

var name: String

Note: You can also use type inference to create it like this – its initial value is the empty string:

var name = ""

Now compute the day of the week’s value and unwrap it with forced unwrapping:

let day = Days(rawValue: dayYear % 7)!

The enumeration’s failable initialiser’s raw value argument is the remainder of the day of the year’s value’s division by 7 – a natural number between 0 and 6.

Note: You could also use an intermediate variable for the day of the week’s value – the initial approach is shorter though:

let dayWeek = dayYear % 7
let day = Days(rawValue: dayWeek)!

Next determine the name of the day inside a switch statement – it maps each enumeration’s case to its corresponding name:

switch day {

  case .monday:

    name = "Monday"

  case .tuesday:

    name = "Tuesday"

  case .wednesday:

    name = "Wednesday"

  case .thursday:

    name = "Thursday"

  case .friday:

    name = "Friday"

  case .saturday:

    name = "Saturday"

  case .sunday:

    name = "Sunday"

}

Note: You can also declare the switch statement like this – the initial approach is simpler because it uses type inference and short dot syntax:

switch day {

  case Days.monday:

    name = "Monday"

  case Days.tuesday:

    name = "Tuesday"

  case Days.wednesday:

    name = "Wednesday"

  case Days.thursday:

    name = "Thursday"

  case Days.friday:

    name = "Friday"

  case Days.saturday:

    name = "Saturday"

  case Days.sunday:

    name = "Sunday"

}

Finally, print the day’s name to the console:

print(name, terminator: "")

You can safely force unwrap the day of the week’s value in this case because it always returns a valid number between 0 and 6. However, it’s good practice and defensive programming to use optional binding instead. The if statement to the rescue!

4. The if conditional binding implementation

Calculate the day of the week’s value and unwrap it with the if let statement:

if let day = Days(rawValue: dayYear % 7) {

}

There is only one thing you should do inside the if statement – determine the day’s name:

switch(day) {

  case .monday:

    name = "Monday"

  case .tuesday:

    name = "Tuesday"

  case .wednesday:

    name = "Wednesday"

  case .thursday:

    name = "Thursday"

  case .friday:

    name = "Friday"

  case .saturday:

    name = "Saturday"

  case .sunday:

    name = "Sunday"

}

Now print the name to the console:

print(name, terminator: "")

The unwrapped value can’t be used outside the if statement – let’s fix this and take the happy path approach with the guard statement.

5. The guard optional binding implementation

Compute the day of the week’s value and unwrap it with the guard let statement:

guard let day = Days(rawValue: dayYear % 7) else {

  abort()

}

If the unwrapping of the value does not succeed you stop the program’s execution with the abort function.

Note: You can’t use return instead of abort here because you are not calling the guard statement inside a function or method.

Next determine the day’s name:

switch(day) {

  case .monday:

    name = "Monday"

  case .tuesday:

    name = "Tuesday"

  case .wednesday:

    name = "Wednesday"

  case .thursday:

    name = "Thursday"

  case .friday:

    name = "Friday"

  case .saturday:

    name = "Saturday"

  case .sunday:

    name = "Sunday"

}

Now print the name to the console:

print(name, terminator: "")

You can now use the unwrapped value outside the guard statement as well – let’s compare the two implementations.

6. If vs guard comparison

If advantages:

  • easy to understand

If disadvantages:

  • unwrapped values can only be used within the scope of the statement

Guard advantages:

  • happy path approach
  • unwrapped values can be used outside the statement as well

Guard disadvantages:

  • difficult to understand

7. Conclusion

Both paradigms have their pros and cons – feel free to try them both and choose the one that suits you best. Happy coding! 🙂

Note: All the code in this tutorial was tested in a playground in Xcode 7.3 and Swift 2.2 (Download).

Advertisements
Posted in Swift

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: