If we have optional values foo
and bar
, Swift will allow us to write:
foo?.doSomething(bar)
Which will evaluate to nil
if foo
is nil
. But it will not let us write:
foo?.doSomething(bar?)
That is, optional chaining only works on the arguments outside a function call, not inside the argument list. (The reasons for this limitation are unclear, but here we are.)
Suppose I want to write an apply
function that lets me move things into the jurisidiction of optional chaining, like so:
bar?.apply { foo?.doSomething($0) }
Here, apply
is a generic function that takes one argument (in this case bar
) and then executes the closure. So if either foo
or bar
is nil, the expression will be nil
.
Here's what I’ve tried:
public protocol HasApply {}
extension HasApply {
public func apply<T>(_ f : (Self) -> T) -> T {
f(self)
}
}
That’s fine as far as it goes. But to make it work, I still have to explicitly apply the protocol to the types I care about:
extension Int : HasApply {}
OK, that makes it work with Int
. But I don’t want to copy & paste for every type. So I try this:
extension AnyObject : HasApply {}
No, that won’t work: the error is Non-nominal type 'AnyObject' cannot be extended
.
Hence the question: is there no way to make this generic function work as a protocol method?
is there no way to make this generic function work as a protocol method?
No, you must "explicitly apply the protocol to the types I care about".
However, you are in fact reinventing the wheel. This is the use case of flatMap
/map
. If both foo
and bar
are optional, you can write:
bar.flatMap { foo?.doSomething($0) }
Note the lack of ?
after bar
. You are calling flatMap
on Optional
, rather than bar
's type. If doSomething
returns T
, the above expression will return T?
.
If only bar
is optional, use map
:
bar.map { foo.doSomething($0) }
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments