What's the difference between constraining protocol conformance to a collection's `Element.Iterator` instead of `Element`?

Reading through this problem in a book "write an extension for all collections that returns the N smallest elements as an array, sorted smallest first, where N is an integer parameter," a solution is given as

extension Collection where Iterator.Element: Comparable {
    func challenge38(count: Int) -> [Iterator.Element] {
        let sorted = self.sorted()
        return Array(sorted.prefix(count))
    }
}

However, I find that removing Iterator also works.

extension Collection where Element: Comparable {
    func challenge38(count: Int) -> [Element] {
        let sorted = self.sorted()
        return Array(sorted.prefix(count))
    }
}

What exactly is the difference, and the meaning of Iterator in this context?

Iterator is an associated type of Sequence (implied by Collection) which provides operations for iterating through the sequence. It has an associated type, Element, which is the type of values produced by the Iterator, which is of course required to be the same type as the type of values in the Sequence. So Iterator.Element just means the same thing as Element.

In very early versions of Swift, protocols couldn't impose that kind of restriction between associated types, so you actually had to write Iterator.Element to talk about the type of values in a Sequence. Sometimes you still see that sort of thing around.

2 Likes