On 13.02.2012, at 01:25, James Maxwell wrote:
> But what I don't get is how hash plays into all this. I've always read that I 
> have to override hash when I override isEqual, but I don't exactly understand 
> what that means or does. What I've done is to make a hash that is equal when 
> two objects have the same values for propA and propB (ignoring propC). That's 
> how I interpreted the few threads I've read about overriding hash...

 A hash is a gatekeeper, a criterion used to discard some of a large number of 
expensive comparisons. The only condition a hash has to fulfill is that if the 
hashes are different, the objects *must not* be equal. If the hashes are 
identical, the objects may or may not be equal.

 It *has to be* like this. Your data consists of probably 8 or 16 bytes, maybe 
more. A hash consists of about 4 bytes. So by that alone, if you go through all 
the permutations of bits in your 16 bytes (all possible values your object may 
contain), some of these must map to the same 4-byte-hash. You only have 4 
billion different hash values, after all. This is what is called a "hash 
collision": Two different objects that result in the same hash.

 When looking for an object identical to another, the hash is simply used to 
eliminate the majority of objects, who *do* have a different hash. A good 
hashing function gives you different hashes for the most common values, while 
rarer values cause more hash collisions. That way, the majority can be quickly 
discarded, leaving you to *really* compare only a few leftover objects that 
happen to collide.

 It's simply a speed optimization in that case.

> But what I need to do in my code, right now, is to copy an object, then alter 
> some properties of the copy, but not the original -- a typical reason for 
> wanting a copy. But I'm seeing that the copy has the same hash and appears to 
> be the same object, since changing properties of the copy changes the 
> original.

 How are you copying this object? What do the instance variables of this object 
contain? The -copy method is not magic. If you have any instance variables that 
are pointers (like objects), you *have to* override -copyWithZone: to make 
copies of those objects as well, if they are mutable. E.g. NSString is 
immutable, so you usually replace an old NSString value with a new one, so you 
can just -retain it, but if it's an NSMutableString, then you need to copy 
that, or both copies of *your* object, even though different, will reference 
(and thus edit) the same mutable string object.

 Collection classes usually perform a shallow copy. That is, if you copy an 
NSMutableDictionary, it will copy the dictionary (so you can modify the list 
without modifying the original list), but will simply retain the objects in the 
array. This is more efficient and usually what's desired, but if you are 
duplicating your entire dictionary hoping to be able to independently edit all 
of your objects in there, you'll have to do it differently and make a deep copy 
yourself.

> So does the system see the matching hashes as identical objects, not just the 
> collection classes?

 No. Try it: Call NSLog( @"%p", theObject ); to log the actual memory address 
of theObject (or just pause in the debugger and note down both addresses). 
Unless you made a shallow copy of a containing object, you will get different 
addresses logged. The hashes will be identical, of course. That's the whole 
point of hashes. If the memory address is identical, it *must* be the same 
object (and NSDictionary probably checks for that by default and considers the 
objects equal right away). Otherwise, it looks at the hash, and if it's 
different, the objects can't be equal. And only if it's neither of those cases, 
it actually compares ivars using -isEqual:.

> Do I have to manually implement some sort of deepCopy method?

 For containers, yes. For your object, -copyWithZone: should be sufficient. Or 
you can grab one from https://github.com/uliwitness/UliKit/ e.g. 
NSDictionary+DeepCopy.m.

> Or, can I just change hash, so that the copy is a different instance, without 
> losing the functionality I need for collections? I don't understand why I'd 
> need to make a deepCopy, since that's what copy is for...


 The hash should be calculated from your object's values. If your object's 
ivars (those that are relevant to the hash) can be changed after creation, you 
must always recalculate your hash whenever one of them is modified (or mark it 
as invalid, and lazily recalculate it whenever someone next asks for the hash). 
If it really is the same object, you goofed and are somehow not copying your 
object. In that case changing the hash will not do much good, as you'll change 
the hash for both places that reference this single object. If you have two, 
the moment you change a value in it, the hash should change as well. If they 
have identical values, they should have identical hashes.

Cheers,
-- Uli Kusterer
"The Witnesses of TeachText are everywhere..."
http://www.masters-of-the-void.com




_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to