Swift Language Associated type requirements

Download Swift Language for free

Example

Protocols may define associated type requirements using the associatedtype keyword:

protocol Container {
    associatedtype Element
    var count: Int { get }
    subscript(index: Int) -> Element { get set }
}

Protocols with associated type requirements can only be used as generic constraints:

// These are NOT allowed, because Container has associated type requirements:
func displayValues(container: Container) { ... }
class MyClass { let container: Container }
// > error: protocol 'Container' can only be used as a generic constraint
// > because it has Self or associated type requirements

// These are allowed:
func displayValues<T: Container>(container: T) { ... }
class MyClass<T: Container> { let container: T }

A type which conforms to the protocol may satisfy an associatedtype requirement implicitly, by providing a given type where the protocol expects the associatedtype to appear:

struct ContainerOfOne<T>: Container {
    let count = 1          // satisfy the count requirement
    var value: T
    
    // satisfy the subscript associatedtype requirement implicitly,
    // by defining the subscript assignment/return type as T
    // therefore Swift will infer that T == Element
    subscript(index: Int) -> T {
        get {
            precondition(index == 0)
            return value
        }
        set {
            precondition(index == 0)
            value = newValue
        }
    }
}

let container = ContainerOfOne(value: "Hello")

(Note that to add clarity to this example, the generic placeholder type is named T – a more suitable name would be Element, which would shadow the protocol's associatedtype Element. The compiler will still infer that the generic placeholder Element is used to satisfy the associatedtype Element requirement.)

An associatedtype may also be satisfied explicitly through the use of a typealias:

struct ContainerOfOne<T>: Container {

    typealias Element = T
    subscript(index: Int) -> Element { ... }

    // ...
}

The same goes for extensions:

// Expose an 8-bit integer as a collection of boolean values (one for each bit).
extension UInt8: Container {

    // as noted above, this typealias can be inferred
    typealias Element = Bool

    var count: Int { return 8 }
    subscript(index: Int) -> Bool {
        get {
            precondition(0 <= index && index < 8)
            return self & 1 << UInt8(index) != 0
        }
        set {
            precondition(0 <= index && index < 8)
            if newValue {
                self |= 1 << UInt8(index)
            } else {
                self &= ~(1 << UInt8(index))
            }
        }
    }
}

If the conforming type already satisfies the requirement, no implementation is needed:

extension Array: Container {}  // Array satisfies all requirements, including Element
Class-Only Protocols