Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift "where" Array Extensions

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?

like image 572
yo.ian.g Avatar asked Jun 10 '15 02:06

yo.ian.g


People also ask

How do you write an array extension in Swift?

For example: var myArray = [Foo]() means that myArray will only contain type Foo . Foo in this case is "mapped" to the generic placeholder Element . If you want to change the general behavior of Array (via extension) you would use the generic placeholder Element and not any concrete type (like Foo).

What are extensions in Swift?

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you don't have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C.

How do I iterate a list in Swift?

You use the for-in loop to iterate over a sequence, such as items in an array. This example uses a for-in loop to iterate over the subviews and set their translatesAutoresizingMaskIntoConstraints to false . There also another variation of looping over a collection, that is forEach(_:) .

What is difference between extension and inheritance Swift?

Only the instances of the subclass can use the new methods. Another diff : In extension, there is no any specific name of extension in swift, but while subclassing there is another name of subclass. In extension, we can not add variables (fields), in subclass it is possible to declare variables.


1 Answers

extension Array {     func filterWithId<T where T : Idable>(id : String) -> [T] {     ...     } } 

defines a generic method filterWithId() where the generic placeholder T is restricted to be Idable. But that definition introduces a local placeholder T which is completely unrelated to the array element type T (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 call self.filter() { ... } with a closure which expects the elements to be Idable.

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):

extension Array where Element : Idable {      func filterWithId(id : String) -> [Element] {         return self.filter { (item) -> Bool in             return item.id == id         }     } } 

Alternatively, you can define a protocol extension method:

extension SequenceType where Generator.Element : Idable {      func filterWithId(id : String) -> [Generator.Element] {         return self.filter { (item) -> Bool in             return item.id == id         }     } } 

Then filterWithId() is available to all types conforming to SequenceType (in particular to Array) if the sequence element type conforms to Idable.

In Swift 3 this would be

extension Sequence where Iterator.Element : Idable {      func filterWithId(id : String) -> [Iterator.Element] {         return self.filter { (item) -> Bool in             return item.id == id         }     } } 
like image 83
Martin R Avatar answered Oct 01 '22 03:10

Martin R