Reputation: 120324
I'd like to use a generic closure in a protocol. For example:
protocol Fetcher {
func fetchWithSuccess<T>(success doSuccess : (T) -> (), failure doFailure : ((NSError?) -> ()))
}
I thought implementing such a protocol would work something like this:
class SimpleFetcher<T> : Fetcher {
let thing : T
init(thing : T) {
self.thing = thing
}
func fetchWithSuccess<T>(success doSuccess : (T) -> (), failure doFailure : ((NSError?) -> ())) {
doSuccess(self.thing) // Fails
}
}
However, the above code fails with error 'T' is not convertible with 'T'
in doSuccess(self.thing)
. What am I missing?
Might be worth mentioning that when using a class there is no problem:
class Fetcher<T> {
func fetchWithSuccess(success doSuccess : (T) -> (), failure doFailure : ((NSError?) -> ())) {}
}
class SimpleFetcher<T> : Fetcher<T> {
let thing : T
init(thing : T) {
self.thing = thing
}
override func fetchWithSuccess(success doSuccess : (T) -> (), failure doFailure : ((NSError?) -> ())) {
doSuccess(self.thing)
}
}
Upvotes: 1
Views: 978
Reputation: 72750
There are 2 things to fix:
Do not make the method generic, because the class is already using generics
The class already defines the T
generic type - if you use <T>
in the method, the T
type has no relationship with the type defined at class level - that explains why you have such a strange error message T is not convertible to T
. To verify that, just change the generic name in the function from T
to something else.
So your function should look like:
func fetchWithSuccess(success doSuccess : (T) -> (), failure doFailure : ((NSError?) -> ())) {
doSuccess(self.thing) // Fails
}
Define a type alias in the protocol
You also have to define a type alias in the protocol, which is conceptually similar to generics for classes and structs (read Type Alias Declaration and Protocol Associated Type Declaration)
protocol Fetcher {
typealias V
func fetchWithSuccess(success doSuccess : (V) -> (), failure doFailure : ((NSError?) -> ()))
}
Upvotes: 2
Reputation: 93276
There are two changes you need to make -- one in your protocol and one in your class.
In the protocol, define a typealias
for the associated type, and have your method use that alias as the type. The methods in a generic class don't need to be generic themselves -- the methods use the generic type of the class itself.
protocol Fetcher {
typealias Element
func fetchWithSuccess(success doSuccess : (Element) -> (), failure doFailure : ((NSError?) -> ()))
}
Then in your class, declare that typealias
to be T
, and remove the generic syntax from the method:
class SimpleFetcher<T> : Fetcher {
typealias Element = T
let thing : T
init(thing : T) {
self.thing = thing
}
func fetchWithSuccess(success doSuccess : (T) -> (), failure doFailure : ((NSError?) -> ())) {
doSuccess(self.thing) // Fails
}
}
Testing:
let s = SimpleFetcher(thing: "Hello")
s.fetchWithSuccess(success: { str in println(str) }, failure: { error in println(error) })
// "Hello"
Upvotes: 3