Having tried it in various languages over the years, the recipe I follow goes like this:
- Static
==function on the base class that calls a normal instance method, usually calledequals(_ other: BaseClass) - Each subclass implements
equalsin a sensible way per its own implementation but the rule is that the other object must have exactly the same type asselfin order to compare equal.
So your class A would have
static func == (a: A, b: A) -> Bool { return a.equals(b) }
func equals(other: A) -> Bool
{
guard type(of: other) == type(of: self) else { return false }
return self.a == other.a
}
And B would have:
func equals(other: A) -> Bool
{
guard let otherAsB = other as? B else { return false }
return self.a == otherAsB.a && self.b == otherAsB.b
}
This is the only way I have found to guarantee symmetry (i.e. a == b implies b == a) and transitivity (a == b && b == c implies a == c).