“if let” considered harmful

  • by

The title is a ripoff of an old classic paper “go to statement considered harmful“. It’s a short read and a good one. The goal of my post is not to make you stop using “if let” and “guard let”. It’s more to make you feel what are you missing when you are using them.

What’s wrong with “if let”?

Nothing. It helps Objective-C developers transition from their “C” concept of nothing to a more modern Swift one. In ObjC it’s called “nil” (it has many more names check out NSHipster post about nil). Swift also has a “nil” literal which is a lie and also should not be used in my opinion 🙂

Handling nothing is a common pattern in ObjC land. You can send a message to a “nil” and you will not crash. The runtime will return you “nil”. If you want you can check if something is nil using == operator in a if statement. Or you can early exit from a function when something is nil. Sounds and looks like a very common pattern. Just check your codebase how many “if/guard let”s you have!

So to help with the transition from ObjC to Swift this special syntax was introduced. But Optional in Swift is something more!

Context

Optional allows you to capture some context in a data structure. In the case of an Optional, this context is the absence of a value or value itself. Also Optional comes with two fantastic methods map and flatMap.

First function map allows you to apply a function to this value and return something else. The next one flatMap does the same thing but this extra step of flattening makes sure that you are only dealing with one level of nesting of optionals when this transformation returns yet another context (Optional).

let number: String? = "42"

let _: Int?? = number.map( Int.init )
let _: Int?  = number.flatMap( Int.init )

Notice the types. When using map we got a double nested optional. That because Int.init has type (String) -> Int?. Using flatMap allows for removing this annoying nesting. If you dig around then you probably will find that function map is defined on Functor. And that function flatMap is defined on Monad. Sometimes you can also hear someone referring to flatMap as bind or monadic binding.

I don’t want to create yet another monad tutorial so I will only say one thing. Think of map and flatMap as design patterns. The first one is how to apply value to a function. The second one is how to chain computations.

Where is the harm?

There are more types that have map and flatMap operations on them but only Optional has this special syntax. Think of Future, Promise, Result, Try, Either, Array, Vapors EventLoopFuture, and more. Today it might not be as much but tomorrow…

Tomorrow Swift might allow us to write code that does not care what type of abstraction is used (Optional, Array, Either…). If we had Higher-kinded Types one day we could write this kind of code. Treating all of them like one structure. Reusing it!

Practice is the best way to learn! Try to use map or flatMap instead of if let and guard let. You can rename flatMap on Optional to andThen to see how your code can be more expressive. There is a beautiful world of composition waiting to be discovered and it’s right before your eyes!

Outuro

Inspired by these functional concepts and wanted to run away from special syntax I have created a Swift Package OptionalAPI. You will find there a good readme, tests, examples on how to use it and a couple of more useful functions.

Cheers 😎

Leave a Reply

Your email address will not be published. Required fields are marked *