Optional.flatMap
and your let
do the exact same thing. Here's its implementation in the standard library, check it out yourself.
To explain why...
It looks like you’re confusing Sequence.map
with Optional.map
.
Despite the same name, there is no iteration happening inside Optional.map
. So why are they called the same? Because they both represent the same monadic operation. Let me explain.
To break it down simply, map
is an abstraction that transforms values inside a container. It takes a Container<Content>
and returns Container<NewContent>
when you give it a closure that turns Content
into NewContent
.
For example:
Optional<Wrapped>
hasfunc map<T>(transform: (Wrapped) -> T) -> Optional<T>
Result<Success, Failure>
hasfunc map<T>(transform: (Success) -> T) -> Result<T, Failure>
Array<Element>
hasfunc map<T>(transform: (Element) -> T) -> Array<T>
Publisher<Output, Failure>
hasfunc map<T>(transform: (Output) -> T) -> Publisher<T, Failure>
The same applies to flatMap
, but it’s used when the closure returns a whole new container. Instead of nesting them as map
would Optional<Optional<Wrapped>>
, flatMap
flattens them to just Optional<Wrapped>
.
Again, this behavior applies to different types:
Optional<Wrapped>
hasfunc flatMap<T>(transform: (Wrapped) -> Optional<T>) -> Optional<T>
Result<Success, Failure>
hasfunc flatMap<T>(transform: (Success) -> Result<T, Failure>) -> Result<T, Failure>
Array<Element>
hasfunc flatMap<T>(transform: (Element) -> Array<T>) -> Array<T>
Publisher<Output, Failure>
hasfunc flatMap<T>(transform: (Output) -> Publisher<T, Failure>) -> Publisher<T, Failure>
Think of Optional
as just another container type and the names map
and flatMap
will make much more sense.
Note: These function signatures are simplified for explanation purposes. In practice, they handle more advanced cases, like rethrowing errors, working with ~Copyable
containers, or returning specialized types such as Publishers.FlatMap or LazyMapSequence.
Fun fact: optional chaining is just syntactic sugar over flatMap
:
let message: String? = "Hello"
message?.min() // Character?
message.flatMap { $0.min() } // Character?