Is it possible to make an Array extension in Swift that is restricted to one class?

Can I make an Array extension that applies to, for instance, just Strings?


As of Swift 2, this can now be achieved with protocol extensions, which provide method and property implementations to conforming types (optionally restricted by additional constraints).

A simple example: Define a method for all types conforming to SequenceType (such as Array) where the sequence element is a String:

extension SequenceType where Generator.Element == String {
    func joined() -> String {
        return "".join(self)
    }
}

let a = ["foo", "bar"].joined()
print(a) // foobar

The extension method cannot be defined for struct Array directly, but only for all types conforming to some protocol (with optional constraints). So one has to find a protocol to which Array conforms and which provides all the necessary methods. In the above example, that is SequenceType.

Another example (a variation of How do I insert an element at the correct position into a sorted array in Swift?):

extension CollectionType where Generator.Element : Comparable, Index : RandomAccessIndexType {
    typealias T = Generator.Element
    func insertionIndexOf(elem: T) -> Index {
        var lo = self.startIndex
        var hi = self.endIndex
        while lo != hi {
            // mid = lo + (hi - 1 - lo)/2
            let mid = lo.advancedBy(lo.distanceTo(hi.predecessor())/2)
            if self[mid] < elem {
                lo = mid + 1
            } else if elem < self[mid] {
                hi = mid
            } else {
                return mid // found at position `mid`
            }
        }
        return lo // not found, would be inserted at position `lo`
    }
}

let ar = [1, 3, 5, 7]
let pos = ar.insertionIndexOf(6)
print(pos) // 3

Here the method is defined as an extension to CollectionType because subscript access to the elements is needed, and the elements are required to be Comparable.


UPDATE: Please See Martin's answer below for Swift 2.0 updates. (I can't delete this answer since it is accepted; if Doug can accept Martin's answer, I'll delete this one to avoid future confusion.)


This has come up several times in the forums, and the answer is no, you can't do this today, but they get that it's a problem and they hope to improve this in the future. There are things they would like to add to stdlib that also need this. That's why there are so many free functions is stdlib. Most of them are work-arounds for either this problem or the "no default implementation" problem (i.e. "traits" or "mixins").


This has already been answered by the three wise-men above ;-) , but I humbly offer a generalization of @Martin's answer. We can target an arbitrary class by using "marker" protocol that is only implemented on the class that we wish to target. Ie. one does not have to find a protocol per-se, but can create a trivial one for using in targeting the desired class.

protocol TargetType {}
extension Array:TargetType {}

struct Foo  {
    var name:String
}

extension CollectionType where Self:TargetType, Generator.Element == Foo {
    func byName() -> [Foo] { return sort { l, r in l.name < r.name } }
}

let foos:[Foo] = ["c", "b", "a"].map { s in Foo(name: s) }
print(foos.byName())