That's pretty common for OO languages (or, in fact, any language with a notion of subtyping), where individual classes implement their own comparison operators. In C++ you can overload the comparison operators, but most OO languages that don't do operator overloading just use a named method. If you write a.equals(b), then you'll call the equals method implemented by the class of a. If you write b.equals(a) then you'll call the method implemented by the class of b. One may know about the other, but the converse is not guaranteed. The Objective-C collection classes document certain invariants for inserting objects into sets (or as keys in a dictionary), including that [a isEqual: b] implies [b isEqual: a] (and that [a isEqual: b] implies that [a hash] equals [b hash]), but this is impossible to statically verify in the general case.