Cocoa. Object equality and hashing clarification

2019-07-27 12:29发布

问题:

I'm studying Cocoa collections currently and my research has brought to Mike Ash's post on object equality and hashing.

Here's an exerpt from the post:

Because of the semantics of hash, if you override isEqual: then you must override hash. If you don't, then you risk having two objects which are equal but which don't have the same hash. If you use these objects in a dictionary, set, or something else which uses a hash table, then hilarity will ensue.

Unfortunately the author doesn't get further in details of what the hilarity will occur and my curiosity doesn't let me just leave it without trying to dig deeper. So the question is: what exactly will happen if i have two equal objects with different hash values and i put these objects into one collection? What sort of problem i will run into?

回答1:

The answer is in this section from Mike's post

A hash table is basically a big array with special indexing. Objects are placed into an array with an index that corresponds to their hash. The hash is essentially a pseudorandom number generated from the object's properties. The idea is to make the index random enough to make it unlikely for two objects to have the same hash, but have it be fully reproducible. When an object is inserted, the hash is used to determine where it goes. When an object is looked up, its hash is used to determine where to look.

In more formal terms, the hash of an object is defined such that two objects have an identical hash if they are equal. Note that the reverse is not true, and can't be: two objects can have an identical hash and not be equal. You want to try to avoid this as much as possible, because when two unequal objects have the same hash (called a collision) then the hash table has to take special measures to handle this, which is slow. However, it's provably impossible to avoid it completely.

What it means is that you will have your 2 objects which claim to be equal. You add the first as the key in a dictionary with some value. Then you try to extract that value using the other object as the key. And it doesn't work. It should, because your objects are equal. But the initial hash lookup failed.

To be clear, this might not happen. It might work fine for some objects and fail for others. The point is, if you don't implement both methods, you don't know what's going to happen.



回答2:

Putting aside the desire to know "why", you should just look at Apple's documentation.

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html%23//apple_ref/occ/intfm/NSObject/isKindOfClass:

If two objects are equal, they must have the same hash value.

All other discussion is interesting from an academic perspective, but fundamentally whether you agree with Apples rules or not, you must abide by them if you want to use the Foundation frameworks.

What Mike and the above poster say seem to be true, for the current incarnation of NSDictionary - there is no guarantee that the same implementation will remain in-place for future releases. However, whatever Apple might replace it with, it will (probably) retain all of the same guarantees and restrictions.