Inconsistent behavior when creating set from equatable enum instances

For example:

enum Foo {
    case a
    case b
}

extension Foo: Equatable {
    static func == (lhs: Foo, rhs: Foo) -> Bool {
        return true
    }
}

let mySet: Set<Foo> = [.a, .b] 
assert(mySet.count == 1) // Sometimes pass, sometimes fail.

Is this a bug or I am using enums incorrectly? Please help!!

If you override Equatable, you should also override other protocols that refine it, including Hashable. Your sample code violates the Hashable requirement (if a == b, then a.hashValue == b.hashValue), so types that use those implementations such as Set would have unexpected behaviors.

It's somewhat obscure here because Swift enum conforms to Equatable and Hashable by default.

2 Likes

Thank you so much that perfectly helped me out!!
However it says hashvalue is deprecated, so I used a hash(into:) function, and it worked well.

Being deprecated only means you shouldn't use it. You should still implement it (correctly), so you should correct both hashInto and hashValue. That said, if you override either of those, the default implementation of the other will pick up your override (not sure how), so you'd be fine either way.

EDIT:

ok, I think you mean the deprecation warning about implementing hashValue itself. Yeah, in that case, you should just override hashInto.

2 Likes

Yeah, they added a default implementation of hashValue that calls hash(into:) so there's no good reason to implement hashValue for new code.