Usage of protocols as array types and function parameters in swift Usage of protocols as array types and function parameters in swift ios ios

Usage of protocols as array types and function parameters in swift


You've hit a variant of a problem with protocols in Swift for which no good solution exists yet.

See also Extending Array to check if it is sorted in Swift?, it contains suggestions on how to work around it that may be suitable for your specific problem (your question is very generic, maybe you can find a workaround using these answers).


You want to create a generic class, with a type constraint that requires the classes used with it conform to SomeProtocol, like this:

class SomeClass<T: SomeProtocol> {    typealias ElementType = T    var protocols = [ElementType]()    func addElement(element: ElementType) {        self.protocols.append(element)    }    func removeElement(element: ElementType) {        if let index = find(self.protocols, element) {            self.protocols.removeAtIndex(index)        }    }}


In Swift there is a special class of protocols which doesn't provide polymorphism over the types which implement it. Such protocols use Self or associatedtype keywords in their definitions (and Equatable is one of them).

In some cases it's possible to use a type-erased wrapper to make your collection homomorphic. Below is an example.

// This protocol doesn't provide polymorphism over the types which implement it.protocol X: Equatable {    var x: Int { get }}// We can't use such protocols as types, only as generic-constraints.func ==<T: X>(a: T, b: T) -> Bool {    return a.x == b.x}// A type-erased wrapper can help overcome this limitation in some cases.struct AnyX {    private let _x: () -> Int    var x: Int { return _x() }    init<T: X>(_ some: T) {        _x = { some.x }    }}// Usage Examplestruct XY: X {    var x: Int    var y: Int}struct XZ: X {    var x: Int    var z: Int}let xy = XY(x: 1, y: 2)let xz = XZ(x: 3, z: 4)//let xs = [xy, xz] // errorlet xs = [AnyX(xy), AnyX(xz)]xs.forEach { print($0.x) } // 1 3