Search code examples
swiftgenericsassociated-types

Where does Array define the Element associated type?


In Swift 2.3 where does Array define the Element associated type ?

It has to define it because it implements GeneratorType which has Element an associated Type. Dictionary and Set both define Element but where does Array define it ?

Array has a generic type called Element, does having a generic type satisfy the GeneratorType protocol ?

I tried this out in the playground and it doesn't work out for me.

For example

protocol Animal{
    associatedtype Breed
}

struct Dog<Breed>: Animal{

}

Solution

  • In Swift 2, Array conforms to CollectionType, which defines the requirement:

    /// Returns the element at the given `position`.
    public subscript (position: Self.Index) -> Self.Generator.Element { get }
    

    Array satisfies this requirement by implementing it like so:

    public struct Array<Element> : CollectionType, MutableCollectionType, _DestructorSafeContainer {
        // ...
    
        // Swift can infer that Self.Index == Int & Self.Generator.Element == Element
        public subscript (index: Int) -> Element
        // ...
    }
    

    This allows Swift to infer that Array's generic placeholder type Element is used to satisfy the associated type Self.Generator.Element, and the concrete type Int is used to satisfy the associated type Self.Index.

    This takes advantage of the fact that associated types can be satisfied implicitly by the type used in the implementation of a protocol requirement in a given type that conforms to that protocol. For example, in your case:

    protocol Animal {
        associatedtype Breed
        var breed : Breed { get }
    }
    
    // I've named the generic placeholder T to simply make clear that Swift is inferring
    // T == Breed and therefore satisfying the associatedtype requirement.
    // You can rename the generic placeholder back to 'Breed' – the compiler will still
    // infer that it's satisfying the Breed associatedtype.
    struct Dog<T> : Animal{
        let breed : T
    }
    
    enum BreedOfCat {/* ... */}
    
    struct Cat : Animal {
        // same principle with non-generic types: BreedOfCat == Breed
        let breed : BreedOfCat
    }
    

    Although of course, if there are no protocol requirements that use the associatedtype, it'll have to be satisfied explicitly with a typealias:

    protocol Animal {
        associatedtype Breed
    }
    
    struct Dog<T> : Animal{
        typealias Breed = T
    }