Equality Design
DO
DO override hashCode
if you override ==
.
The default hash code implementation provides an identity hash — two objects generally only have the same hash code if they are the exact same object. Likewise, the default behavior for ==
is identity.
If you are overriding ==
, it implies you may have different objects that are considered “equal” by your class. Any two objects that are equal must have the same hash code. Otherwise, maps and other hash-based collections will fail to recognize that the two objects are equivalent.
DO make your ==
operator obey the mathematical rules of equality.
An equivalence relation should be:
-
Reflexive:
a == a
should always returntrue
. -
Symmetric:
a == b
should return the same thing asb == a
. -
Transitive: If
a == b
andb == c
both returntrue
, thena == c
should too.
Users and code that uses ==
expect all of these laws to be followed. If your class can’t obey these rules, then ==
isn’t the right name for the operation you’re trying to express.
AVOID
AVOID defining custom equality for mutable classes.
When you define ==
, you also have to define hashCode
. Both of those should take into account the object’s fields. If those fields change then that implies the object’s hash code can change.
Most hash-based collections don’t anticipate that—they assume an object’s hash code will be the same forever and may behave unpredictably if that isn’t true.
DON'T
DON’T check for null
in custom ==
operators.
The language specifies that this check is done automatically and your ==
method is called only if the right-hand side is not null
.
class Person {
final String name;
// ···
bool operator ==(other) => other is Person && name == other.name;
int get hashCode => name.hashCode;
}
class Person {
final String name;
// ···
bool operator ==(other) => other != null && ...
}