3

When I change an object in a set to match the other object in the set do they now merge?

When I have a set of 5 sobjects, and they are all unique objects (unique Signatures) I add them to a Set, giving me set.size() = 5

Then I edit a field on one of those objects to be the same, so that now 2 of those object signatures are exactly the same. However it does not merge them together. I now have 2 exact same items in my set.

If I set.addall(originalSet) to another set they do merge and now I have 4 items, so this proves they were exactly the same.

contact c1 = new contact(id='003000000089012', firstname='1', lastname='2', phone=null);
contact c2 = new contact(id='003000000089012', firstname='1', lastname='2');
contact c3 = new contact(id='003000000089012', firstname='1', lastname='2', phone='');
contact c4 = new contact(id='003000000089012', firstname='1', lastname='3', phone='');
contact c5 = new contact(id='003000000089012', firstname='1', lastname='3');

set<contact> contacts = new set<contact>();
contacts.add(c1);
contacts.add(c2);
contacts.add(c3);
contacts.add(c4);
contacts.add(c5);
for(contact c : contacts){
 system.debug('5 Items:  '+c);
}
 system.debug('5 Items BREAK');

c1.phone='';

for(contact c : contacts){
 system.debug('Same :  '+c);
}
 system.debug('Same BREAK');

contacts.add(c1);

for(contact c : contacts){
 system.debug('c1 Added:  '+c);
}

 system.debug('c1 Added BREAK');

contact c6 = new contact(id='003000000089012', firstname='1', lastname='2', phone='');
contacts.add(c6);

for(contact c : contacts){
 system.debug('New Same:  '+c);
}
 system.debug('New Same BREAK');

contacts.addall(contacts);

for(contact c : contacts){
 system.debug('Addall:  '+c);
}
 system.debug('Addall BREAK');

set<contact>  cnts2 = new set<contact>();
cnts2 = contacts.clone();

for(contact c : cnts2){
 system.debug('Clone:  '+c);
}
 system.debug('Clone BREAK');

set<contact>  cnts3 = new set<contact>();
cnts3.addall(contacts);

for(contact c : cnts3){
 system.debug('New Addall:  '+c);
}
 system.debug('New Addall BREAK');
  • @RedDevil What is weird here is the two records which are same are returning same hashCode. You can check hashcode using System.hashCode() also it is said in the document that Uniqueness of all other non-primitive types is determined by comparing the objects’ fields. – Mr.Frodo May 17 at 7:00
7

Equality and the hash code value are based on all the properties of the SObject which makes sense.

But when an object is placed in a hashMap, the hash code is used to determine which "bucket" the object reference is placed in at add time. So if you then change any property of the object after that, it is highly likely that the object reference will be lost because the hashMap logic expects it to be in the bucket corresponding to the new hash code but it is actually in the bucket corresponding to the old hash code.

I wouldn't describe this behavior as a merge because things like the size of the hashMap will not change. Best to not modify - mutate - objects that are already in sets. Even if your logic works today, you will probably trip up future development done on that area of the code tomorrow. Some overview e.g. here To mutate or not to mutate?

There is an SObject-specific nasty case: if you put SObjects in a set before they are persisted, persisting them will set an Id in the SObjects and your set will be broken in any following logic.

See e.g. Hash table for illustrated examples of how hashMaps work.

  • just for my understanding so if we place 2 instances of same sobject in set will they be treated same or different? – RedDevil May 17 at 8:04
  • Hi @RedDevil, If they have exactly the same properties set, they will be treated as the same. Chaos comes when a property is changed after an object is added to the set. – Keith C May 17 at 8:34
  • Thanks was just trying to understand this better – RedDevil May 17 at 8:48
0

This may be part of the answer: https://docs.oracle.com/javase/7/docs/api/java/util/Set.html

Extract from the above document: "Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set. A special case of this prohibition is that it is not permissible for a set to contain itself as an element."

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.