I have the following simple class hierarchy: A conforms to Hashable and has a single subclass B. Adding distinct instances to a Set (or a Dictionary) results in a weird behaviour because the generic element of Set is internally calling static func == (lhs: A, rhs: A) -> Bool
(instead of the one defined on B) while the hashValue is correctly evaluated on the overridden implementation of B. As a result the set will contain unexpected elements. Things get worst with the new non-deterministing value of hashValue in Swift 4.2, causing the set to contain either 1 or 2 elements depending on the seed value.
How does one properly handle class hierarchy and conformance to Equatable?
class A: Hashable {
let a: Int
init(a: Int) { self.a = a }
static func == (lhs: A, rhs: A) -> Bool { return lhs.a == rhs.a }
func hash(into hasher: inout Hasher) { hasher.combine(a) }
}
class B: A {
let b: Int
init(a: Int, b: Int) {
self.b = b
super.init(a: a)
}
static func == (lhs: B, rhs: B) -> Bool { return lhs.a == rhs.a && lhs.b == rhs.b }
override func hash(into hasher: inout Hasher) {
hasher.combine(a)
hasher.combine(b)
}
}
let b1 = B(a: 1, b: 2)
let b2 = B(a: 1, b: 3)
var set = Set<B>()
set.insert(b1)
set.insert(b2)
print(set.count) // sometimes 1, sometimes 2