3

I am coding a system where I have objects which represent a set of resources. These resources are identifiable (they have an ID). There can only be one resource with the same ID, and so multiple objects with the same ID really should have the same values.
My problem is with the equality concept in this case. Should it be based on the ID or on the values alone? Is object A = object B because they have the same ID OR should object A == object B because their fields are the same.

One possibility I was thinking of was to have the ID-based comparison be "equals" and the field-based comparison be "equivalent". Alternatively I could have it so the field-based comparison was "equals" and the ID based comparison was "representSameObject" (or something). Just a pseudo-code example:

class A {
   String uuid;
   int field1;
   double field2;
   List<String> listField;

   @Override
   public boolean equals(Object other) {
       return uuid.equals(other.uuid);
   }

   public boolean equivalent( other ) {
       if (this == other) {
           return true;
       }
       if (null == other) {
           return false;
       }
       if (other.getClass() != this.getClass()) {
           return false;
       }

       A rhs = (A) other;
       return new EqualsBuilder().append(field1, rhs.field1).append(field2, rhs.field2).append(listField, other.listField).isEquals();
   }
}

In the end this may come down to a personal preference coupled with system requirements, but I am very interested to learn how others have approached this concept. It has been annoying the heck our of me since I started on this project!

If it makes a difference I am programming at the minute in Java. I don't mind where the answer comes from though as this is obviously a conceptual issue.

  • I would suggest looking into how to correctly implement the equals() method in java because yours in this state would throw a NullpointerException if 'other' was null. Also your uuid is a string, so you probably wanted to do a uuid.equals(other.uuid)? Make sure you understand the difference between '==' and equals(). – c_maker Jun 14 '13 at 12:07
  • @c_maker Thanks but as I said it is just pseudo-code. I do know the difference between == and equals, although I do bemoan the lack of operator over-riding in Java. I'm just looking for how to approach the concept. I'll update the answer to represent java code though. thanks. – Dennis Jun 14 '13 at 12:09
  • Cool beans. My conscious is clear :) – c_maker Jun 14 '13 at 12:13
1

One thing you can do is to look at how ORM frameworks, like Hibernate handle these situations. I believe by default 'domain objects' (objects that can be persisted) get an id as well as an equals() and hashCode() (that use the provided id for equivalence) by default.

They do suggest however that if you want to use these domain objects in collections, you should always override their provided equals() and hashCode() methods.

So maybe it's a matter of context. I believe that Hibernate uses the ids to see if it has a persisted object already. If the id is null, it will try to do an 'insert' versus if the id is not null, it will try to look up the persisted object and update its fields. If the id is not found, that is an error condition.

I hope this answer at least points you to some direction.

  • Yes, that's helpful. I didn't think to investigate those kinds of frameworks for inspiration. – Dennis Jun 14 '13 at 13:12
4

You should actually go one step further and consider it an error if there are two distinct objects that both represent the resource with ID X. This means that if you have two references to the object for ID X, then the two references should compare equal with the == operator (which compares reference equality in Java).

Allowing multiple objects to represent one and the same resource inevitably results in the objects becoming out-of-sync and bugs because different parts of the system having different, incompatible, views on the state of the resource.

Also, if you use the reference equality as a check for resource identity, then you could could use the equals method to check if two resources happen to have the same value at that moment.

  • Thanks for your answer. I will consider that but I think my situation is complicated by the fact that I am using a distributed cache from which the resource can be queried. This means that the real state of the resource is in the cache and local processors will have copies of it. However the suggestion may be valid, in that equals could perhaps incorporate both the check on the UUID as well as the fields. Still not 100% about what to do. – Dennis Jun 14 '13 at 12:12
0

If Bob is now wearing a blue hat instead of red hat (the one he was wearing yesterday) he is still Bob. So blue hat Bob equals red hat Bob.

I stick to keeping my equals to being identity based. Wether Bob has changed I keep in a different method or interface.

  • 1
    But if Bob was wearing prison suit 430321 on Monday but due to a mix-up at the laundry was wearing prison suit 430123 on Tuesday is he Bob, or prisoner 430123, or prisoner 430321? – Dennis Jun 13 '14 at 17:27
  • @Dennis: Defining what identity means is important. If Bob was the name of the person who was wearing suit 430321, then on Tuesday Bob would be the person wearing 430123. If, however, the name Bob was attached the the suit 430321, but also served as shorthand for "whoever is wearing 430321", then on Tuesday Bob would be the person in 430321 (whoever that happened to be) or--if the suit was empty--a "dead" reference [not a dangling reference, since the suit would still exit]. – supercat Oct 22 '14 at 22:19
  • @supercat Hey... yeah I agree it is important to define it. I'm not saying that my comment is correct just that it is important how we represent identity in the system. Ideally unique objects should be represented by unique instances, but how can we define that uniqueness. Bob is Bob, but why is he not Fred? It's not his name obviously, and it is not his hat. Really for a person you are looking at his genetics and progenitors. Then you get into clones! Is BobClone really Bob? Are they "equal" despite being separate instances? It's an interesting problem. – Dennis Oct 28 '14 at 10:13
  • @Dennis: I would define two things as encapsulating the same identity if it is possible they (or the things identified thereby) might appear to change together, but would never be observed as changing separately. If only one reference exists to an object, it has no meaningful identity; objects whose state can never change would encapsulate no meaningful identity but for the fact that Java and .NET allow certain aspects of an object's state to be changed outside its control. – supercat Oct 28 '14 at 16:03
  • An extremely important, but often overlooked, aspect of an object's state is the existence (and whereabouts) of things that identify it. If a reference to an object is stored as a key in an IdentityHashMap, adding information to the associated value will add it to the object's effective state. As a consequence, even though immutable objects should have no identity, all types of references in Java can be used to encapsulate identity whether the types in question want them to or not. – supercat Oct 28 '14 at 16:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.