Why hashCode and operator== Must Be Overridden Together
Overriding `==` without `hashCode` breaks collections like `Set` and `Map`. If two objects are equal, they MUST have the same hash code. This is vital for custom classes used as map keys or set elements.
WHY IT EXISTS By default, Dart's == operator checks for object identity: are two variables pointing to the exact same object in memory? For custom classes that represent values (like a coordinate point), we often need to define our own logic for equality based on their internal state. Hash-based collections like Map and Set need a consistent and efficient way to handle this custom equality.
THE MENTAL MODEL Think of hashCode as a quick, preliminary check for equality. A Set or Map first compares hash codes to place objects into buckets. If two hash codes are different, the objects are definitely not equal, and the process stops. If the hash codes are the same, the collection then uses the more expensive operator== to confirm if they are truly equal. If you define == but not hashCode, two "equal" objects might have different hash codes, so the == check is never even attempted.
HOW IT WORKS The contract is simple: if a == b is true, then a.hashCode must equal b.hashCode. To implement this, you override both. First, override operator== to compare the significant fields of your class, ensuring the other object is of the same type. Then, override the hashCode getter to compute an integer based on those same fields. A modern, safe way to combine field hash codes is using Object.hash(field1, field2, ...).
WHEN TO USE IT Override both whenever you create a class that represents a value, and you expect two different instances with the same internal state to be treated as equivalent. This is crucial for Data Transfer Objects (DTOs), configuration objects, or any custom class you intend to store in a Set or use as a key in a Map.
WHEN NOT TO USE IT You don't need to override these for classes where object identity is what matters. For example, service classes, controllers, or Flutter Widgets often rely on their specific instance identity. In these cases, the default behavior is correct and sufficient.
ONE CANONICAL EXAMPLE Imagine a Person class with name and age. We want two Person instances to be equal if their name and age match. First, we override == to check if the other object is a Person with the same name and age. Then, we override hashCode to generate a value from those same properties, for example: @override int get hashCode => Object.hash(name, age);. Now, Set<Person> will correctly identify and store only unique people.
Read the original → dart.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.