Extensions with a generic where clause

protocol Container {

associatedtype Item: Equatable

mutating func append(_ item: Item )

var count: Int { get }

subscript(i: Int) -> Item { get }

}



extension Container where Item == Double {

func average() -> Double {

var sum = 0.0

for index in 0..<count {

sum += self[index]

}

return sum / Double(count)

}

}

print([1260.0, 1200.0, 98.6, 37.0].average()) // Prints "648.9"




What does the bold part mean?

Does it mean "add this average() method requirement to the Container protocol whose associated type Item is of type Double" ?

or does it mean "add the average() method to the conforming types of Container whose Item is of type Double" ?

Is this extension adding a method requirement to the Container protocol itself, or is it adding this method to the types who conform to Container ?


Also, the last line of code uses the average() method on an array of Double values. But how is that even possible? does this array even conform to the Container protocol??

Accepted Answer

Well, it's not a generic where clause. Even if you mean "generic" in a non-technical sense, it's not generic because it's actually specific. The bold line declares an extension to the Container protocol in the specific case where the associated type is Double.


An extension can simply add more requirements to a protocol. Without a "where" clause, that just means the extension is written in two parts. With a "where" clause, the extension only applies in matching contexts, as if you had declared a separate DoubleContainer sub-protocol.


The declaration of "average()" in the extension is something kind of separate. It doesn't add any requirements to the protocol. Instead, it defines a default implementation for the requirement in the original protocol declaration. Any type that conforms to Container (of Doubles) will have a fully functioning average function, and so doesn't have to supply its own. If it does supply its own, that replaces the default one for that type. (Note that this doesn't mix well with class inheritance. It only applies to the base class that declares the conformance.) Swift currently accepts default implementations only in an extension, not in the original protocol declaration.


I don't know why the last line works for you. I tried the above code in a playground, and the last line doesn't compile ("Value of type '[Double]' has no member 'average'"). My guess is that you have something else that results in type inference leading to this result.

Thanks that clarifies things a lot.


The reason why I thought this was a generic where clause is because I found this under the "Extensions with a Generic Where Clause" section of the Apple Swift manual thing.


here's the link: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-ID179

In that case, the extension is for a type (Stack), not a protocol, and the type is in fact generic.


Your example was an extension of a protocol, which cannot be generic.


The two things are loosely related, though. An associated type in a protocol is something similar to a type parameter in a generic type, and the effect of the "where" clause is similar in concept.


The difference is that a generic type is actually a family of distinct types sharing a "the same" name, whereas a type conforming to a protocol with an associated type is only a single type with a unique name.

Extensions with a generic where clause
 
 
Q