Reputation: 19106
Swift is unable to infer the return type of a function, whose parameter is a closure, and where the return type is deduced from the closure´s return type.
Given this generic class:
class Bar<T> {
init(_ v:T) {}
func wrap<R>(f:()->R) -> Bar<R> {
return Bar<R>(f())
}
func wrap(f:()->()) -> () {
f()
}
}
The function wrap
is overloaded, once taking a Closure as parameter which returns ()
, and another time taking a Closure as parameter which returns a type specified as a type parameter (R
) for the function.
In the following snippet, it seems obvious that the return type of the Closure passed as an argument to the function wrap
is a String
:
var bar :Bar<Int> = Bar<Int>(0)
let b0 = bar.wrap {
return ""
}
IMHO, the compiler should now be able to deduce the return type of wrap
as type Bar<String>
, and thus should be able to infer the type of the constant b0
accordingly.
The compiler (as of beta 3) issues the following errors:
main.swift:53:16: error: type '()' does not conform to protocol 'StringLiteralConvertible'
return ""
^
main.swift:51:9: warning: constant 'b0' inferred to have type '()', which may be unexpected
let b0 = bar.wrap {
^
main.swift:51:9: note: add an explicit type annotation to silence this warning
let b0 = bar.wrap {
^
: ()
Either of this workaround would fix the issue:
let b1 = bar.wrap {
() -> String in
return ""
}
let b2:Bar<String> = bar.wrap {
return ""
}
Edit: added Antonio's answer as another version which compiles correctly:
let b0 = bar.wrap { "" }
The question is:
Is there a compelling reason for the compiler not being able to infer the return type in the failing examples, assuming it is working as specified?
Again, please consider this:
works: let b0 = bar.wrap { 0 }
fails: let b0 = bar.wrap { return 0 }
Or, is this possibly the effect of an incomplete or incorrect implementation of a beta status compiler?
Note: Please, do not state your opinions here, only clear facts - if any. ;)
Upvotes: 3
Views: 4547
Reputation: 72760
Maybe what you're looking for is the implicit return from single expression closure:
let b0 = bar.wrap { "" }
Addendum
There might be a lot to say for one method to work and not the other.
The book doesn't make any mention of a shortcut using just return
and a value. But that works when expliciting the generic type
let b2:Bar<String> = bar.wrap { return "" }
On the other hand, in the Inferring Type from Context paragraph of the swift book, when talking about type inference there's no mention of generics, so I wouldn't be surprised if type inference doesn't work when combined with generic types in this case.
Keeping reading book:
This parameter is expecting a function of type (String, String) -> Bool. This means that the String, String, and Bool types do not need to be written as part of the closure expression’s definition
That doesn't mean (but it could) that this won't work:
() -> (T)
where T
is a generic type.
That said, I think that
let b0 = bar.wrap { return "" }
doesn't work because there's a generic type involved in the equation. What follows is my opinion, but you should read it anyway. It's possible that this:
let b0 = bar.wrap { "" }
works but it shouldn't. Meaning that it works, but it's a bug, it should produce a compiler error. Does that make any sense?
Upvotes: 5