let onSuccess has an implicit type of () -> (Void?), vs when it’s inlined the compiler can look at the function signature and deduce that it’s () -> Void.
can you explain what it's deducing? the type of the closure returns Void? in both cases. If the compiler can deduce that we can make a Void? closure into Void when inline, shouldn't it accept all Void? closures for Void
// inlining the closure succeeds
doThing(completion: {
onResponse?(.success)}
)
benefits from the type context provided by the completion parameter. The closure can be type-checked as () -> Void by ignoring the return value. But in this version:
let onSuccess = {
onResponse?(.success)
}
There's no context to infer the () -> Void type for the closure, so the compiler is treating it as a single-expression closure with a return value, and analyzes the type of the onResponse?(.success) expression to pick the return type.
Of course, inferring a type of () -> Void? here is pretty silly. We probably ought to warn that this is happening and ask for an explicit type annotation or return statement to clarify your intent. You can resolve this either by declaring let onSuccess: () -> Void or having a return appear after the onResponse call.
No, it is different. I rewrite your with type annotations to make it clear.
func doThing(completion: () -> Void) {}
enum Response {
case success
case failure
}
var onResponse: ((Response) -> Void)? // here the closure itself is optional, it can be nil.
// So it is effectively an
var onResponse: Optional<((Response) -> Void)> // usage:
// if let closure = onResponse {
// closure(.success) // can call it here
// } else {
// // no closure, nothing to call
// }
let onSuccess: () -> Optional<Void> = {
onResponse?(.success)
} // here we have a non-optional closure, we can call it without if-let dance.
// But this closure can return either Void or nil
// So:
// 1) onResponse is an Optional-type instance containing either closure (or function) or nil
// 2) onSuccess is a function that return optional value (Optional<Void> value)
// ERROR: Cannot convert value of type '() -> Void?' to expected argument type '() -> Void'
doThing(completion: onSuccess) // error as expected
// completion is of type `() -> Void` but onSuccess is of type ` () -> Optional<Void>`
// inlining the closure succeeds
doThing(completion: { // – as expected, because `() -> Void` closure type is inferred from `doThing(completion:)` function
onResponse?(.success)}
)
You can rewrite `onSuccess` like this:
let onSuccess: () -> Void = { // explicit function type
onResponse?(.success)
}
let onSuccess = {
onResponse?(.success)
return // explicit return
}