As of Swift 2.0 it seems we can get closer to extensions of generic types applicable to predicated situations.
Although we still can't do this:
protocol Idable {
var id : String { get }
}
extension Array where T : Idable {
...
}
...we can now do this:
extension Array {
func filterWithId<T where T : Idable>(id : String) -> [T] {
...
}
}
...and Swift grammatically accepts it. However, for the life of me I cannot figure out how to make the compiler happy when I fill in the contents of the example function. Suppose I were to be as explicit as possible:
extension Array {
func filterWithId<T where T : Idable>(id : String) -> [T] {
return self.filter { (item : T) -> Bool in
return item.id == id
}
}
}
...the compiler will not accept the closure provided to filter, complaining
Cannot invoke 'filter' with an argument list of type '((T) -> Bool)'
Similar if item is specified as Idable. Anyone had any luck here?
defines a generic method
filterWithId()
where the generic placeholderT
is restricted to beIdable
. But that definition introduces a local placeholderT
which is completely unrelated to the array element typeT
(and hides that in the scope of the method).So you have not specified that the array elements must conform to
Idable
, and that is the reason why you cannot callself.filter() { ... }
with a closure which expects the elements to beIdable
.As of Swift 2 / Xcode 7 beta 2, you can define extension methods on a generic type which are more restrictive on the template (compare Array extension to remove object by value for a very similar issue):
Alternatively, you can define a protocol extension method:
Then
filterWithId()
is available to all types conforming toSequenceType
(in particular toArray
) if the sequence element type conforms toIdable
.In Swift 3 this would be