Hi, I'm trying to make some optional unwrapping using Optional.map but I'm finding some strange behavior when I try to map nested Optional values. Here is an example:
struct Foo {
let attr: Int?
}
let f: Foo?
f.map { $0.attr }
.map { attr in
// attr here is Int? should it be Int because previous map?
}
The behavior is intended? If so, why it only works with the first level optional?
Optional<A>.map takes a function (A) -> B and returns an Optional<B>. Optional<A>.flatMap takes a function (A) -> Optional<B> and returns an Optional<B>.
So, if we just follow the types, we see that since the closure { $0.attr } is a function (Foo) -> Optional<Int>, passing it to Optional<Foo>.map would return a value of type Optional<Optional<Int>>, while passing it to Optional<Foo>.flatMap would return a value of type Optional<Int>.
This is why, in this case, flatMap works for you.
In fact, the flatMap + flatMap + ... + map pattern is quite common in functional programming precisely because it allows you to chain sequences of operations that all return wrapped structures (in this case, wrapped in optionals), while only having a single wrapper at the end. Some languages have extra syntactic sugar for that.
To some extent, Swift also has some syntactic sugar around that with optional chaining (although that is limited to variable/method lookup), so in this case you might even simply write f?.attr.map { ... }, or even f?.attr?.somethingDefinedOnInt (like f?.attr?.magnitude).