Home > Software design >  Making an enum Equatable in Swift
Making an enum Equatable in Swift

Time:02-20

Here is my sample code for making my enum explicitly conform to Equatable protocol:

enum TestEnum: Equatable {

    case one, two, three, four, five

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

I used hashValue to control but I do not understand how could I be able access to hashValue? I mean at least I did not make my enum conform to Hashable, so why should I be able to access to hashValue in first place?!

So my real question or issue is this, let say my enum is not conforming to Hashable, how could I return true or false for == function in this case?

So think about in this way we do not have access to .hashValue, what could be able do in this case?

As you can see my enum conform just for Equatable nothing else!

CodePudding user response:

An enum without associated values conforms implicitly to Equatable and Hashable.

From the documentation:

Hashable

When you define an enumeration without associated values, it gains Hashable conformance automatically, and you can add Hashable conformance to your other custom types by implementing the hash(into:) method.

Equatable

An enum without associated values has Equatable conformance even without the declaration.

If you don't trust the documentation prove it:

enum TestEnum {
    case one, two, three, four, five
}

Equatable:

TestEnum.one == TestEnum.one // true
TestEnum.one == TestEnum.three // false

Hashable:

let dict : [TestEnum:Int] = [.one:1, .two:2]
// compiles, a dictionary key must be hashable

And hashValue is discouraged in Swift anyway.

CodePudding user response:

To chime in:

If you did want to implement == yourself, the way to do it would be with pattern matching. Surprisingly (to me), the code below seems to call neither ~= nor ==.

enum TestEnum: Equatable {
    case one, two, three, four, five

    static func ==(lhs: TestEnum, rhs: TestEnum) -> Bool {
        switch (lhs, rhs) {
        case (.one, .one),(.two, .two), (.three, .three), (.four, .four), (.five, .five): return true
        default: return false
        }
    }
}

That does kind of make sense. At bottom, you need the system to provide a way to compare these values. If one didn't exist all, it would be impossible for you to build one. By analogy, imagine how you might implement == for Int, if it wasn't already built-in. It would be impossible.

I'll also add: it doesn't make any sense to implement == based off hashValue. hashValue speeds up search algorithms by allowing them to rapidly cull a massive part of their search space. For example, say you're looking for milk in the grocery store. A good hashValue for a grocery product might be the section its in. If you saw that your milk's hashValue was "dairy", then you know right away that there's no point searching the deli, meat, produce and frozen food isles. But once you're in front of the dairy isle, you start linearly searching through all the items there. This is where == comes in. It needs a more granular notion of equality than the heuristic that hashValue provides. Butter and milk are both dairy, but you need to be able to discern them apart.

  • Related