Referencing operator function '==' on 'Equatable' requires that 'Dictionary<U, V?>.Values' conform to 'Equatable'

816 Views Asked by At

I have a class that defines a dictionary:

class InventoryDictionary <U : Hashable, V> : Equatable {

    var dictionary : [ U : V? ]  = [:]

    static func ==(lhs: InventoryDictionary, rhs: InventoryDictionary) -> Bool {
       return    lhs.dictionary.keys == rhs.dictionary.keys
              && lhs.dictionary.values == rhs.dictionary.values
    }
}

XCode shows an error:

Referencing operator function '==' on 'Equatable' requires that 'Dictionary.Values' conform to 'Equatable'

I'm trying to make InventoryDictionary conform to the Equatable Swift protocol.

In the == overload function, dictionary.keys can be compared for equality but not the values (which is understandable, kind of).

But it isn't clear to me from the message whether or not that's solvable without me writing code to check each V (value) or whether there's some way to make Swift-generic V equatable.

What's a good approach to this?

2

There are 2 best solutions below

0
Sulthan On BEST ANSWER

First of all, V must be Equatable, too. That is, the declaration should be

class InventoryDictionary<U: Hashable, V: Equatable> : Equatable {

However, you shouldn't use a class. Preferably you should use a struct for this use case because then equability will be generated for you.

struct InventoryDictionary<U: Hashable, V: Equatable> : Equatable {
    var dictionary: [U: V] = [:]
}

If you really need this to be a reference type:

class InventoryDictionary<U: Hashable, V: Equatable> : Equatable {
    var dictionary: [U: V] = [:]

    static func ==(lhs: InventoryDictionary, rhs: InventoryDictionary) -> Bool {
        return lhs.dictionary == rhs.dictionary
    }
}

Note that I have also removed the optional from the dictionary value. It shouldn't be there unless you really really want to store keys with a nil value.

0
Alexander On

To add to Sulthan's answer:

If the hashability and equability of V aren't intrinsic to the InventoryDictionary (i.e. they're only needed for the conformances to Hashable and Equatable), then you can use conditional conformances:

// `U` has to be `Hashable` in any case, because it's used as a key
class InventoryDictionary<U: Hashable, V> {
    var dictionary: [U: V?] = [:]

    // ...
}

extension InventoryDictionary: Equatable where V: Equatable {}
extension InventoryDictionary: Hashable where V: Hashable {}