## Mapping and flatMapping optionals for cleaner code

Aug 4 · 3 min read

At this stage, you might know that Swift `Optional`s are just `enum`s on steroids:

`enum Optional<Wrapped> {  case none  case some(Wrapped)}`

In fact, you can use the long form to use them:

`let longFormSomeOptional = Optional<Int>.some(1)let longFormNoneOptional = Optional<Int>.none`

You might also know how to use `Optional` binding (`if let`, `guard let`, and `switch`), `Optional` chaining, the nil-coalescing operator, and forcing unwrapping.

But, you might not know some other operations explained below that can make your life easier.

# Mapping an Optional

There’s a map operation in the `Optional` `enum` that allows us to map its unwrapped value:

`func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U?`

This function evaluates the closure when the `Optional` is not `nil`, passing the unwrapped value as a parameter. It returns the result of the closure, or just `nil` when the `Optional` is `nil`.

Let’s see an example:

`let someNumber: Int? = 2let noneNumber: Int? = nil// closure will be evaluated and result1 is Optional(4)let result1 = someNumber.map { \$0 * \$0 }// closure won't be evaluated and result2 is Optional(nil)let result2 = noneNumber.map { \$0 * \$0 }`

If we use `map` along with the nil-coalescing operator, we have a great alternative for an ugly `var-if-let-else`:

`let someNumber: Int? = 2let noneNumber: Int? = nil// closure will be evaluated and result1 is 4let result1 = someNumber.map { \$0 * \$0 } ?? 0// closure won't be evaluated and result2 is 0let result2 = noneNumber.map { \$0 * \$0 } ?? 0`

# Optional Binding With Map

There’s a particular use of the `map` function for `Optional`s that I think is good to know.

If we check the `map` signature again:

`func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U?`

We can see that when `U` is `Void`, the map would return nothing (formally `Void?` or `()?`). As a consequence, we can use the `map` here as `Optional` binding.

Let’s see an example:

`func log(_ message: String) {  print(message)}let someMessage: String? = "Hello World"let noneMessage: String? = nil// closure will be evaluatedsomeMessage.map { log(\$0) }// closure won't be evaluatednoneMessage.map { log(\$0) }`

We’re not formally mapping the optionals above, but rather using it as an alternative of `if-let`, in case this fits better in your code.

# FlatMapping an Optional

Let’s say the previous transform closure returns an optional. Then, `map` would return a double optional.

`let someString: String? = "2"let result1 = someString.map { Int(\$0) } // result1 is Int??`

In that case, you might want to `flatMap` the optional instead, so the closure result is flattened.

`func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?`

`let someString: String? = "2"let result1 = someString.flatMap { Int(\$0) } // result1 is Int?`

In the same way that I mentioned with the `map` operation, we can use `flatMap` with the nil-coalescing operator as an alternative for an ugly `var-if-let-else`.

`let someString: String? = "2"let noneString: String? = nil// closure will be evaluated and result1 is 2let result1 = someString.flatMap { Int(\$0) } ?? 0// closure won't be evaluated and result2 is 0let result2 = noneString.flatMap { Int(\$0) } ?? 0`

Written by