How can I extend typed Arrays in Swift?

arrays, swift

Solution

For extending typed arrays with classes, the below works for me (Swift 2.2). For example, sorting a typed array:

class HighScoreEntry {
    let score:Int
}

extension Array where Element == HighScoreEntry {
    func sort() -> [HighScoreEntry] {
      return sort { $0.score < $1.score }
    }
}

Trying to do this with a struct or typealias will give an error:

Type 'Element' constrained to a non-protocol type 'HighScoreEntry'

Update:

To extend typed arrays with non-classes use the following approach:

typealias HighScoreEntry = (Int)

extension SequenceType where Generator.Element == HighScoreEntry {
    func sort() -> [HighScoreEntry] {
      return sort { $0 < $1 }
    }
}

In Swift 3 some types have been renamed:

extension Sequence where Iterator.Element == HighScoreEntry 
{
    // ...
}

Problem

How can I extend Swift's `Array<T>` or `T[]` type with custom functional utils? Browsing around Swift's API docs shows that Array methods are an extension of the `T[]`, e.g: ``` extension T[] : ArrayType { //... init() var count: Int { get } var capacity: Int { get } var isEmpty: Bool { get } func copy() -> T[] } ``` When copying and pasting the same source and trying any variations like: ``` extension T[] : ArrayType { func foo(){} } extension T[] { func foo(){} } ``` It fails to build with the error: Nominal type `T[]` can't be extended Using the full type definition fails with `Use of undefined type 'T'`, i.e: ``` extension Array<T> { func foo(){} } ``` And it also fails with `Array<T : Any>` and `Array<String>`. Curiously Swift lets me extend an untyped array with: ``` extension Array { func each(fn: (Any) -> ()) { for i in self { fn(i) } } } ``` Which it lets me call with: ``` [1,2,3].each(println) ``` But I can't create a proper generic type extension as the type seems to be lost when it flows through the method, e.g trying to replace Swift's built-in filter with: ``` extension Array { func find<T>(fn: (T) -> Bool) -> T[] { var to = T[]() for x in self { let t = x as T if fn(t) { to += t } } return to } } ``` But the compiler treats it as untyped where it still allows calling the extension with: ``` ["A","B","C"].find { $0 > "A" } ``` And when stepped-thru with a debugger indicates the type is `Swift.String` but it's a build error to try access it like a String without casting it to `String` first, i.e: ``` ["A","B","C"].find { ($0 as String).compare("A") > 0 } ``` Does anyone know what's the proper way to create a typed extension method that acts like the built-in extensions?

Original source

Related problems