I have a class A which conforms to Equatable and a class B which inherits from A. I defined == for each of these classes.
When comparing two B objects, the correct == function is used to determine the equality. When checking to see whether an array of B contains an object B, the == defined for A will be called.
//: Playground - noun: a place where people can play
class A: Equatable {
var id: Int
init(id: Int) {
self.id = id
}
}
class B: A {
}
func ==(lhs: A, rhs: A) -> Bool {
print("Comparing using A's ==")
return false
}
func ==(lhs: B, rhs: B) -> Bool {
print("Comparing using B's ==")
return lhs.id == rhs.id
}
let b1 = B(id: 1)
let b2 = B(id: 2)
let array: [B] = [b1, b2] // an array explicitly defined as containing B objects
print("\((b2 == b2))")
print("\(array.index(of: b2))")
print("\(array.contains(b2))")
Output:
Comparing using B's ==
true
Comparing using A's ==
Comparing using A's ==
nil
Comparing using A's ==
Comparing using A's ==
false
Why is this happening?
EDIT: SOLVED!
As Hamish commented below, this is because B will rely on A's == in certain cases, for more, see here, point #2: == overload for custom class is not always called
To work around this I did the following: I defined a method called isEqualTo(object:)
that is called from A's ==
. That method is overridden from B.
This is probably a little bit more inefficient because of the overhead of going through another few method calls, but it works good enough for the data I am dealing with.
//: Playground - noun: a place where people can play
class A: Equatable {
var id: Int
init(id: Int) {
self.id = id
}
// define an isEqualTo method which takes another A instance
// this will be called from A's ==
func isEqualTo(object: A) -> Bool {
return self == object
}
}
class B: A {
// override the isEqualTo: method
override func isEqualTo(object: A) -> Bool {
// if we are actually dealing with an object of type B, cast it
// first, then call B's ==
if let bObject = object as? B {
return self == bObject
}
// fallback to A's ==
return super.isEqualTo(object: object)
}
}
func ==(lhs: A, rhs: A) -> Bool {
print("Comparing using A's ==")
// use a designated, overridable method to determine equality
return lhs.isEqualTo(object: rhs)
}
func ==(lhs: B, rhs: B) -> Bool {
print("Comparing using B's ==")
return lhs.id == rhs.id
}
let b1 = B(id: 1)
let b2 = B(id: 2)
let array: [B] = [b1, b2]
print("\((b2 == b2))")
print("\(array.index(of: b2))")
print("\(array.contains(b2))")
Output:
Comparing using B's ==
true
Comparing using A's ==
Comparing using B's ==
Comparing using A's ==
Comparing using B's ==
Optional(1)
Comparing using A's ==
Comparing using B's ==
Comparing using A's ==
Comparing using B's ==
true