How to understand this conditional conformance in the Standard Library?

I noticed the following in the generated interface for Set's contains in the Standard Library:

extension Set : Sequence where Element : Hashable {

    /// Returns an iterator over the members of the set.
    public func makeIterator() -> SetIterator<Element>

    /// Returns a Boolean value that indicates whether the given element exists
    /// in the set.
    ///
    /// This example uses the `contains(_:)` method to test whether an integer is
    /// a member of a set of prime numbers.
    ///
    ///     let primes: Set = [2, 3, 5, 7]
    ///     let x = 5
    ///     if primes.contains(x) {
    ///         print("\(x) is prime!")
    ///     } else {
    ///         print("\(x). Not prime.")
    ///     }
    ///     // Prints "5 is prime!"
    ///
    /// - Parameter member: An element to look for in the set.
    /// - Returns: `true` if `member` exists in the set; otherwise, `false`.
    ///
    /// - Complexity: O(1)
    public func contains(_ member: Set.Element) -> Bool
}

I'd like to understand why it's declared as a conditional conformance.

(I mean, a Set is always a Sequence and Set.Element is always Hashable anyway, so why this conditional conformance?)

2 Likes

Set is first declared only with a Hashable constraint on its generic parameter. In conforms to everything else (including SetAlgebra, Collection, ExpressibleByArrayLiteral, etc) in extensions.

Concerning the Sequence part, I believe this is a way of conforming to a complex protocol hierarchy – You first conform to P, then, in a separate extension, you conform to P1: P and so on:

protocol P { func foo() }
protocol P1: P { func soo() }

struct Foo  {
 ...
}

extension Foo: P {
    
    func foo() {}
}

extension Foo: P1 {
    
    func soo() {}
}

Set first conforms to Sequence, then to Collection in separate extensions, adding functionality step by step.

Regarding the Hashable part, I understand your concern. It is redundant to constrain the generic parameter to Hashable in every extension for a trivial reason: struct Set<Element> where Element: Hashable

Nevertheless, the compiler doesn't complain about an equivalent example in a playground. IMO, this should produce a redundant constraint warning.

P.S. Xcode 9.2 (Swift 4.0) does show a redundant constraint warning, although accompanied by the error of unsupported conditional conformances.

2 Likes

Interesting! As far as I can tell, this is a bug in SourceKit's rendering of the generated interface. Set's Sequence conformance is declared unconditionally here: swift/Set.swift at main · apple/swift · GitHub

2 Likes

Filed SR-7413 to track this.

2 Likes

Also filed a diagnostics improvement for redundant conformance constraints in conditional conformances – SR-7414