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.
Interview question
If a custom class overrides operator== but not hashCode, what is the primary consequence when its instances are used in a Set or as Map keys?
- a.Object comparisons will become significantly slower across the entire application, regardless of collection type.
- b.Hash-based collections may fail to correctly identify equal objects, leading to unexpected behavior like duplicates or missing elements.Correct
- c.All equality checks, including those outside of hash-based collections, will revert to comparing object identity.
- d.The Dart compiler will report a compile-time error due to the contract violation.
Why? this is the answer
The core contract states that if two objects are equal by operator==, they must have the same hashCode. If hashCode is not overridden, two logically equal objects might have different hash codes, causing hash-based collections to treat them as distinct. This is a runtime logical error, not a compile-time error.
Just read this? Test yourself on what you have been reading.
Read the original → dart.dev
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on dart — each one lists the topics its interview covers.
See open roles