Optional Binding: A Nice Feature in Swift

I absolutely hate assignment statements in conditional statements. I’ve been burned by it so many times in the past, especially when I was first starting to write code. However Swift has managed to make me like it.

Risky Pattern

I find that one of the most common beginner mistakes in software is accidentally forgetting to add a single ‘=’. In other words, someone writes a nice little if statement like this:

if (banana == result()) {
  //branch a
} else if (banana = result2()) {
  //branch b
} else if (banana == result3()) {
  //branch c

In the above example, the error is clearly:

banana = result2()

In context, this is an obvious mistake. For branch A and branch C, the developer clearly wanted to compare banana to the various results, but accidentally overwrites it’s value half way through. Hawkward. This will result in all kinds of bugs. For example, branch c is likely to never get hit because of this. In these obvious cases, often a static analysis tool or manual code review will catch it. Otherwise, tests will do the job, hopefully.

However, it’s less clear what the developer expects when you have a single branch like this:

if (banana = result()) {
  //Do some stuff

Was it intentional? Or was it a mistake? It’s easy to argue that some basic tests would ensure that this developer hadn’t gone astray here… However let’s say that the person before you didn’t write any tests, and you’re left trying to figure out what’s going on. This is just unnecessary work that can be avoided by simply avoiding assignment in conditionals like this, in my opinion.

Optional Binding in Swift

However, in Swift this behaviour is encouraged. You can do what’s called optional binding. If you aren’t familiar with the concept of optionals, read up on the basics. They’re a really neat feature of the language that lets you tell the compiler that a variable may or may not have a value. This does a fairly good job at eliminating the dreaded NullPointerException or, null dereference, or unexpected behaviour because a variable was nil when you didn’t expect it, etc. It does this by forcing you to explicitly state whether or not you expect the value to exist or not (using the ! or ? operators). However awesome this is, this basically results in a ton of exclamation marks and question marks littered all over your code. This visually resulted in some really excited or confused code.

Optional Binding lets you get away from having to add those extra operators in the following nasty bit of code:

if banana != nil {

Instead, you declare a constant in the condition and avoid having to explicitly say “yes, this actually exists”.

if let realBanana = banana {

It cleans things up a bit. I’ve come to really like this.  Not only must you be explicit about it being an assignment with the keyword let but it eliminates the extra unwrapping work in the code block AND it lets you define a constant for your variable, all in a single statement. Despite my initial reluctance to use this (based on the risky pattern), I’ve come to accept this as a really nice way to clean things up. The reason for the change of heart stems from how explicit this is. This guarantees that the assignment wasn’t a mistake.

Optional binding can also be used to avoid this sea of question marks:

label?.text = "Banana"
label?.font = UIFont.systemFontOfSize(13.0)
label?.textColor = UIColor.blackColor()

Instead, you can do this (not necessary, but if you hate question marks…):

if let bananaLabel = label {
  bananaLabel.text = "Banana"
  bananaLabel.font = UIFont.systemFontOfSize(13.0)
  bananaLabel.textColor = UIColor.blackColor()

Cleaner, sort of. I think this latter example boils down to your own personal preferences. Use optional binding where it makes the most sense.

All of this to say: optional binding is a really neat feature in Swift. I like optionals because of how explicit it causes the language to be, however it tends to litter the code with exclamation marks and question marks. Optional binding is a nice way to mitigate it and I suggest you embrace it. However, you must remember that even if the condition fails, the methods in the condition are still invoked. If there are any side effects to invoking those methods, then use this at your own risk!

EDIT: BONUS MATERIAL – Other Cool Syntax

After I wrote this I was reminded by a limitation that I should have mentioned. If you’ve tried to treat the optional binding syntax as a boolean value, you’ll have likely hit a compiler error. The following block is NOT valid and will not compile.

if let banana = someValue && error == nil {
  //Do stuff

However, you can do this somewhat nasty trick with the good ol’ comma (,) operator:

if error == nil, let banana = someValue {
  //Do stuff

This will behave as you expect. When error is nil, and someValue is not nil, stuff will be done. Otherwise, the expression fails and the branch is skipped. However, I personally dislike this syntax. It’s a little choppy and it doesn’t read that nicely. This, of course, is a personal preference. Instead, I fall back on the where operator.

if let banana = someValue where error == nil {
  //Do stuff

I can only assume that this is syntactic sugar for the previous style. This reads a lot nicer but you will still need to rely on the comma (,) operator to have multiple ‘lets’ in a single condition:

if let banana = someValue where error == nil {
  //Do stuff

Happy optional binding!