Since the outer closure returns Int?
, the nil-coalescing operator ??
is inferred to return Int?
as well. Thus its right-hand side 0
is promoted to Int?
and its left-hand side is inferred to be Int??
(but see note at bottom).
That left-hand side of ??
is the return value of a closure, so the closure is inferred to have type () -> Int??
. That closure returns the result of calling an inner closure, which has type () -> Int?
and returns nil
.
So the innermost closure returns nil as Int?
which is the enum value Optional<Int>.none
. The middle closure promotes that value to Int??
by wrapping the enum value Int?.none
in another layer of optionality, where it becomes Optional<Int?>.some(.none)
.
The nil-coalescing operator then sees a non-nil value of type Int??
, whose value is .some(.none)
, so it unwraps that value and returns what is inside. The value inside, of course, is Optional<Int>.none
, and its debug description is simply nil
.
• • •
However the standard library actually contains two different nil-coalescing operators. Both take T?
on the left, but on the right one takes T
and the other takes T?
. The reason why the second one exists is to allow chaining things that each return optional, but because it does exist you can annotate the middle closure to use it.
If you put () -> Int? in
at the start of that closure, or as Int?
after calling it (just before the ??
operator), then the compiler will use the T?
version of ??
. This results in the middle closure returning Optional<Int>.none
without wrapping it again, so the ??
operator then sees an empty optional and returns its right-hand side, which is Optional<Int>.some(0)
.
Or, alternatively, you could put as Int
after the integer literal 0
. This prevents the compiler from promoting it to an optional, and thus the ??
operator has Int
on the right so it must have Int?
on the left and the closure type gets inferred accordingly.