Search code examples
swiftgenericsdictionarycomparisonequality

Comparing dictionaries containing actually equatable types, based on non-equatable data structures


So I want to equate two dictionaries of the same type [AnyLanguage: SortedList<String>].
AnyLanguage conforms to Hashable, and therefore also Equatable, so it's not a problem. SortedList on the other hand does not conform to Equatable, as it is generic over Element, which has no restrictions:

public struct SortedList<Element> { ... }

Now, I have implemented the equality operator for SortedList, when its Elements conform to Equatable:

public func ==<T: Equatable>(left: SortedList<T>, right: SortedList<T>) -> Bool

Now, when comparing two of the aforementioned dictionaries:

let dictA: [AnyLanguage: SortedList<String>] = [:]
let dictB: [AnyLanguage: SortedList<String>] = [:]

dictA == dictB

I get the following error:

Error

I assume that the compiler is complaining because SortedList does not conform to Equatable, even though I have implemented the comparison operator for equatable Elements (which SortedList<String> would be able to use, as String is equatable).

How can I compare the two dictionaries?


Solution

  • The == operator for dictionaries requires that both Key and Value type conform to Equatable.

    You have implemented a (restricted) == operator for SortedList<Element>. But implementing a == operator for a type does not make that type Equatable automatically. The conformance must be declared explicitly.

    Unfortunately, it is (currently) not possible to make SortedList<Element> conform to Equatable only if Element is Equatable. The same problem exists for arrays, compare Why can't I make Array conform to Equatable? for a discussion in the Apple developer forum.

    The only solutions – as far as I know – are to make SortedList<Element> conform to Equatable unconditionally (as in Cristik's answer), or to define a custom comparison operator for dictionaries

    func ==<Key : Equatable, T : Equatable>(lhs: [Key : SortedList<T>], rhs: [Key : SortedList<T>]) -> Bool {
        // ...
    }