Does evolving a class over time a concern in regards to equals implementations?

Viewed 61

If we have a class that on creation had implementation of the equals and hashCode.
Later the class was enhanced with new fields and when this happens most likely the equals/hashCode should be updated too.
My question is that an anti-pattern? Could there be some issues e.g. if the class is in some library and there is some code that considers the old contract for example?

3 Answers

I would not consider this as anti-pattern. What you describe is how a program's code is evolving. Classes get updated with more features and bug fixes.

In your case, hashCode usually is used to check object equality just like an implementation of an equals method. Assuming that the old code used a part of the total class' attributes, it the equality checks should remain the same as the old code is not aware of the new attributes and these are not assigned in any object.

However, when a class is updated and is used by third party code that cannot be tested (e.g. the class is part of a maven project published in a maven repository), the third party code should use the class/project's version to ensure compatibility. Personally, I have seen many cases where a maven project is updated and the new version contains exactly the same class/method signature with a totally different implementation that breaks the code.

They need to be updated if the contract for the equality of the class changes, yes. Let's say you add middleName to a User class, and you want equality to be based on the first, middle and last name, instead of just first and last. However adding fields that don't affect equality won't need changes.

The only code involved is the code in equals() and hashcode(), so unless you've written some bad code (e.g. not using equals, but manually comparing fields), any existing code works transparently.

Yes, it's a concern when modifying any implementation.

When developers use your type, they'll develop based on the current contract. If updating the implementation does not change the contract, you're fine.

However, if updating the implementation does change the contract, you aren't fine.


If your contract for equality is currently:

"Two objects are equal if they share the same name"

The two objects should always be equal if they have the same name, since developers will develop based on that.

If you introduce a new field, for example id, and update the contract to include that field:

"Two objects are equal if they share the same name and id"

Systems which expected equality by name will now break if two objects share the same name, but have different ids.

This is not the fault of that developer. Your contract stated equality was determined by names. Their code abided that. By updating the contract, you will potentially break their code.


If your contract stated:

"Two objects are equal if all their properties are equal"

Then introducing a new property shouldn't break software, as developers would expect any new properties to be accounted for by the implementation, and would develop their systems with that in mind.

Related