The Monad Among Us

The concept of “nil” does not exist in Swift (despite the existence of the keyword nil!). But a language that can’t represent the absence of a value wouldn’t be much use, so the duties of nil have been given to the Optional type. Why is this a good thing, you may ask? Well, it vastly increases the safety of the language, because all values are guaranteed to be non-nil unless declared to be Optional.

The naive use of Optionals would overwhelm a codebase with the repetitive boilerplate used to unwrap values. To mitigate against this, the much feared monad can be used to simplify things by abstracting away the boilerplate.

To prevent people from running away in fear, Apple refrain from mentioning that the Optional type is a monad, and that Optional chaining is a monadic bind operation. During this talk, I hope to demonstrate the different ways that monadic bind appears in Swift, and that it is a concept which simplifies the use of Optionals. There is no reason to fear!

For an extended exploration of the concept, view this repository on GitHub.


The “M” Word (0:00)

Hello! I obviously didn’t get the memo, because nobody has been mentioning the “M” word, and then, my slides immediately say “Monad”… Sorry! So, I’ve had a quick change of title, just so nobody need panic: “The Soft Fuzzy Thing”. Let’s get straight into it!

nil is a Polymorphic Superhero (0:25)

This is a Swift Summit, and it’s good to have a quote from Chris himself, the Creator. Unfortunately he couldn’t be here tonight. It’s a quote that no one else is using, because I made it up. I’m sure he’d approve. “In Swift, nil is a polymorphic superhero”. And you might think, “That’s a bit strange!”. You know, Chris is probably saying this all the time in private. And you might think, “Well, I like Swift, but if Chris is making such strange comments then maybe I should just stick to Objective-C, something a bit weird is going on here…”

Let me convince you that this is a very sensible statement. If you think of a super hero, they’ve usually got two identities, the run of the mill, day-to-day one, and then all the action happens when they change. The polymorphic bit means a nil can become any sort of superhero. Your usual hero can become Batman, or Wonder Woman, or whatever, whereas with nil it can become all of them. As long as it satisfies the type checker, of course.

Name That nil (1:30)

We’ll play a quick game to prove this strange idea. It’s called “Name that nil in one”, or, “What’s that type of nil?” To make sure everyone is familiar, it will involve optionals, which are just an enum with two cases: it’s either None, or Some with an associated value. It’s no more complicated than that.

x = nil (1:43)

To start off, x = nil. This is an easy one, we actually declared our type there. We’ve declared it as an optional Bool — you probably wouldn’t use that normally — but the nil… what is nil? Well, if you give it the full type, we’ve got an optional of type Bool with the xvalue of None. You don’t really have the nil, it’s an optional.

let x:Bool? = nil

let x = Optional<Bool>.None

String to Int (2:19)

Next one: let’s say we have a String, we want to try and convert it to an Int — this is something that you may actually use, you’d go “Is this equal to nil?” because this operation actually produces an optional. But is it really nil after compile time? Well, again, it’s going to be optional, but this time it’s an Int, and the value is None (again). That’s what you’re comparing it to, it’s not really a nil. Honestly, I’m not making it up.

"9".toInt() != nil

"9".toInt() != Optional<Int>.None

map(nil) (2:51)

This next one, you’d never use, this is completely insane. We’re trying to map over nil, and within the function we’re adding a string. With type inference, what we actually have is an optional string. That’s what it is after it’s compiled. The compiler is not going to be happily treating nil, it needs the optional, so that’s its type.You can see this weird double identity, superhero status, the nil once compilation takes place isn’t really nil.

map(nil) { $0 + "!" }

map(Optional<String>.None) { $0 + "!" }

nil < 0 (3:27)

Here’s a nice easy one. We’ve got nil < 0, there’s not too much code there. And you think: on the right-hand side it’s an Int, obviously. Well actually, after compilation here it won’t be an integer. That sounds a bit scary. nil becomes an optional Int of None, and on the right-hand side just so it can actually compile and type-check, we have an extra mechanism in play. We have an optional Int of Some(0)! I don’t have time to actually go in and explain that, because I’d be off on a different tangent.

nil < 0

Optional<Int>.None < Optional<Int>.Some(0)

NilLiteralConvertible (4:13)

What I’m trying to get across is that nil always becomes something else. How does that happen? How do you get an optional from nil? It’s NilLiteralConvertible. What really happens it that you have this protocol, Optional has the protocol, so any time the compiler needs to ask an optional “I’ve got a nil, can you create me a value?”, Optional can. It just creates a value with None as the default, which is obviously sensible.

protocol NilLiteralConvertible {
  init(nilLiteral: ())
}
enum Optional<T> : NilLiteralConvertible {
  init(nilLiteral: ()) {
    self = None
  }
}

nil is a Phantom (4:42)

Hopefully, with that very brief game of “Name that nil” I’ve given you the idea that nil is a phantom, which is a very good idea, because if you escape from the Land of the nils in many languages, you have nils popping up all over the place. So you need to take precautions, you have to check for nil in various functions. Whereas if you have a String in Swift it’s a String, and if you pass that to a function you don’t need to check within the function if someone has passed you nil. For the return value you can be guaranteed to get a string. You’re not going to get nil. It brings a bit more sanity.

A Mandatory Ridiculous Code Example (5:33)

I’m going to show you a mandatory ridiculous code example that just fits on a slide. All we have here is a dictionary, with multiple embedded dictionaries, and at the end we have a “hello”. Just to play with an idea here, for a language with nil you have to ask yourself one question: “do I feel lucky?”. You can subscript in your favorite imperative language that will return nil if your key doesn’t exist in the dictionary. You can go along there, subscripting 1, 2, 3, 4, 5. If you are lucky, it’s all great, you will get “hello” as you’d expect. If you fall at the final hurdle, then you will get nil as your final response, which may not be catastrophic, but you need to take that into consideration afterwards. This nil may cause trouble. If you subscript in and you fall over before you even get to the end, Then you’re going to have an exception, and that’s not too good.

let dict = [1:[2:[3:[4:[5:"Hello"]]]]]
let v = dict[1][0][3][4][5]

// Possible results:
// 1. v == "Hello"
// 2. v == nil
// 3. Boom!!!

You’d never use this kind of code, but if dictionary subscripting can return nil, you’ll have these values which you need to consider, which is a bit strange. The same happens in Swift: dictionary subscripting doesn’t return nil, it returns an optional. If your key doesn’t exist, you will have an optional of None. If it does exist, you will have an optional with the value embedded in it.

As a reminder, optionals are simple. If you remove nil, and replace it with an optional of either case None or Some, that’s not a big change. It’s a really simple idea.

Again, in Swift (6:55)

How would that look in Swift? If you’ve not actually written any Swift, then probably look away now. If you have, please don’t leave the room, or throw things at me. This does make sense.

struct Dictionary<Key:Hashable, Value> {
  subscript (key: Key) -> Value?
}

In Swift style, we need to switch completely through the dictionary. We do our first subscripting of one, which returns an optional. We can’t subscript again, so we have to type-check with the switch to make sure it’s not None. If it’s not None, then we can do the same thing again. We need to subscript, we need to check whether that optional has a value. Again, we have a vast amount of code.

let v = dict[1]?[2]?[3]?[4]?[5]

When you next ask, “What did optional chaining ever do for us?”, it removes that. That’s the magic. Syntactically it’s not that different from the unsafe version, whereas here we just have these question marks appended in.

Monadic Bind(s)! (8:45)

Here’s where the “M” word turns up… So what is it? It’s “Monadic bind!”. Amazing, I said the “M” word! Frightening. Optionals are the Green Piste of the Monadic Mountain. The Monadic Mountain can get a bit hairy, but with optionals you probably won’t break a leg if you look into, say, the monadic nature of chaining functions that return optionals.

The Custom Infix Operator (9:03)

Think of the Monty Python Spanish Inquisition sketch, “No! Not the comfy chair!”, then that’s the kind of tone you should have when you say “No! Not the custom infix operator!”. It’s going to be very relaxed. To declare it, it’s quite simple, and not particularly interesting. Declare the usage of our infix operator, which is called bind (usually). Let’s get to the nitty gritty of it.

We have the function, and it has two generic parameters: the first parameter is an optional of A?, then we supply a function A -> B?, and the final return value of the function is an optional B?. You have to think, how do we put these pieces together to return the value that we actually want? What you will notice is that we can’t pass the first parameter to our function A -> B?, because it’s an optional A?. What we need to do, really, is look at our first parameter, and check if it’s actually None, rather than a Some value. We don’t actually apply the function, and we return None from the bind. Whereas if it does contain a value, we can apply the function, and all is good with the world.

The Simplicity of Abstraction (10:22)

When you saw all that boiler code that we had for the Swift version, with pattern matching to go through the dictionary, you can abstract all that away into this one operator. If our first parameter is None, we return None. If it does actually contain a value we apply the function, and we get back a sensible value.

To compare and contrast, here, we have the usual form. I’m not suggesting this is how you do optional chaining, this is a demonstration that we can define the operation ourselves, to know what this question mark is doing. This is a limited form of monadic bind, because it only really works for methods and subscripting. If you have nested properties that have optionals, you can use the question mark to burrow your way through.

If we compare the optional bind, it’s doing exactly the same thing, apart from we need to pass a function on the right-hand side of the bind. We do our dictionary, we do the lookup, and then, on the left-hand side the dictionary with a first subscript of 1, that returns an optional. That goes through the bind operator, which expects our function, which then does the next subscript too. That will return, in turn, an optional, which we feed into the next bind, and we feed into the next bind, and we feed into the next one. These are two completely equivalent things. It’s interesting to show that, behind the scenes of the special optional chaining question mark, there is something relatively simple going on.

Two Monadic Binds are Better than One (12:17)

Again, in Swift, for some reason two monadic binds are better than one. We have if let syntax, in Swift 1.2, letting you unwrap multiple optionals. You can do a monadic bind type thing with them, because they can rely on previous values.

let v:String?
if let a = dict[1], b = a[2], c = b[3], d = c[4], e = d[5] {
    v = e
} else {
    v = .None
}

This is certainly not something you’d ever do, but again, it’s just to say that if let syntax is a more generalized form of optional chaining. Do your if let syntax, do your subscripting, so you get your first value, which you bind to A, and then next time you subscript with the A, and bind to B. If any of these things fail, the else clause would occur, and then you would return the None statement. If it all succeeds, then you get to the final value.

This crazy if let version, and the optional chaining, are entirely equivalent — you’d never use if let in this way, but it’s just to show that these concepts are actually intimately connected.

A Third Monadic Bind! (13:33)

I was on holiday, and they released another Beta… And flatMap appeared! As they say, you wait around for monadic bind, then they start popping up all over the place. So now, three monadic binds! Apparently better than one.

How does that look? On Optional it is defined as a method, the first argument is implicit, because it’s a method on Optional. You have a function that goes from T -> U?. In usage, it looks uncannily similar to our scary infix operator, with the “pointy pointy equals”, or “bind”. You’ll see that flatMap and the infix operator are incredibly similar. flatMap could be used for optional chaining — you never would, but this is just to say that these things are intimately connected.

enum Optional<T> {
    func flatMap<U>(f: T -> U?) -> U?
}

It’s strange that there are so many binding methods. flatMap is more general, you can apply a function, rather than just call a method with it.

nil is Dead! Long Live the Optional! (14:53)

To conclude, the nil is dead! Long live the optional! Code without nil is saner code, because, everywhere else you can be absolutely certain that nil’s are not going to be popping up to cause havoc. Optionals are simple values, but they do add complexity, and the monadic bind is a natural way to tame that complexity. If you remember, that huge amount of code we needed to do the pattern matching with the switch statements, monadic bind abstracts away the slightly complicated boilerplate code, and makes your life a lot easier.

Swift deals with optionals monadically, and so do you, but you may not realise it. The “M” word is unspoken, but it’s there!

And that’s it. The end!



Al Skipp

Al Skipp