-2

Standard object modelling identifies attributes, aggregates and associations of objects. You must conform to several requirements when implementing the equals() method of a class. There is plenty of advice available on how to write this method, including pitfalls to avoid. But I couldn't find any advice indicating whether you should or should not examine associations when implementing equals(). It is clear to me that you should examine attributes and aggregates.

Should you examine associated objects in equals()? That is, should equality depend on associated objects?

Community
  • 1
  • 1
Raedwald
  • 46,613
  • 43
  • 151
  • 237
  • Object associations can have circular references, which can cause problems: http://stackoverflow.com/questions/8863308/implementing-equals-and-hashcode-for-objects-with-circular-references-in-java – Raedwald Jul 11 '13 at 19:53

4 Answers4

1

While I think it is generally a good idea to avoid basing equality on associations, I would argue that this does not apply in all cases. While it is a good rule of thumb, there are likely a number of cases where this rule breaks completely.

It is entirely dependent on the domain and what it means for two objects to be equal. For example:

If you have a cohort of students, taught by a teacher, you could determine equality by requiring that another cohort must contain the same students be (pair-wise equal) and be taught by the same teacher. In that case, the cohort's equality is strictly dependent on each of it's pieces being equal.

cdeszaq
  • 30,869
  • 25
  • 117
  • 173
0

Equality should not depend in any way on associated objects, therefore equals() should not examine associates. It should not even depend on the identity of associates, or even whether an object has an association. I'm surprised that this advice is not explicitly stated often enough for me to have found it.

  • From an object modelling point of view, it is natural to consider two things with different associations to be equivalent. If a mad scientist were to create an exact duplicate of me, we would say the doppelgänger and I were "the same" (equivalent), even though we had different fathers (different fathered-by associations). The doppelgänger might not even have a father (if the scientist were more mad physicist than mad biologist).

  • Examining associations introduces practical problems. There is the danger of bi-directional associations (spouse-of, for example) causing infinite loops. There is the performance hit of indirect associations requiring examination of potentially all objects in the working-set: if your Person objects have parent-of and child-of associations, Person.equals() would actually tell you whether family trees were equivalent.

Community
  • 1
  • 1
Raedwald
  • 46,613
  • 43
  • 151
  • 237
  • I would argue that this statement does not apply in all cases. While it is a good rule of thumb, there are likely a number of cases where this rule breaks completely. It is entirely dependent on the domain and what it means for two objects to be equal. If part of my object's equality requires it to refer to another object that is also equal to the same object of my equal, then that requirement is a counter-example to your rule. – cdeszaq Sep 29 '11 at 19:05
  • @cdeszaq could you provide a concrete example? – Raedwald Sep 29 '11 at 19:07
0

in general perhaps not. but how about a car that has frame, body, engine, wheels etc. one could consider different implementations of equals.

Ray Tayek
  • 9,841
  • 8
  • 50
  • 90
  • I'd say that the care was an aggregate-of those components, not that the car was associated-with them. – Raedwald Sep 29 '11 at 19:15
0

Short answer: make equals() do what you need it to do. But be careful.

Where the class may be used as a key in a HashMap (or stored in a HashSet), equals() must be constant for the time that it's in the map. This suggests that, in order to avoid a lot of analysis and/or bugs, classes used as HashMap keys should restrict equals() to effectively immutable fields - including associations.

You also must ensure that any equals-included associated object has a similarly immutable-for-contained-scope equals() implementation, and doesn't do an equals() back on the original object, causing runaway recursion.

Ed Staub
  • 15,480
  • 3
  • 61
  • 91
  • "effectively immutable fields": and it can be trouble-some to set up associations in the constructor (bi-directional associations, for example), so that is a reason to be wary of using associations. – Raedwald Sep 29 '11 at 19:30
  • I disagree. `equals` should reflect the equality of the object. Defining equality based on mutable fields is just fine. It's up to whatever is using an object as a key to insure that its value will not change over time (or not use it in a hash-based collection). Using your logic, we should never define equality on a mutlable object, because it could be used in a hash-base collection. – Steve Kuo Sep 30 '11 at 00:21
  • @Steve, I think you misunderstood, or I wrote poorly, or both... where I wrote "restrict equals() to effectively immutable fields", it was in the context of the preceding sentence - where the object is being held in a HashMap. I updated the sentence to be sure this is clear. Does that address your objection? – Ed Staub Sep 30 '11 at 01:52
  • "make `equals()` do what you need it to do": well, yes, correctly implement your detailed design. My question is a detailed design question: should you design the equivalence relation to be sensitive to associations. – Raedwald Sep 30 '11 at 09:05
  • 1
    @Raedwald - "correctly implement your detailed design" - No, that's not what I meant. Your detailed design is in response to slightly larger-scale contextual requirements. These are what I was trying to refer to by "what you need it to do". I was arguing for a pragmatic, context-sensitive decision-making approach, rather than trying to say whether this is "good" or "bad" in general. – Ed Staub Sep 30 '11 at 14:32