Copying, hash, and isEqual:
Copying, hash, and isEqual:
- Subject: Copying, hash, and isEqual:
- From: "b.bum" <email@hidden>
- Date: Sun, 6 Jun 2004 10:03:34 -0700
Subject changed -- this is not to comment upon NSDictionary's
documented behavior of copying its keys. If that doesn't suit your
needs, create a CFDictionary with the appropriate behavior and cast it
to NSDictionary.
This message focuses specifically upon -hash, -isEqual: and copying.
>
If there is one "invariant" a dictionary should obey, it is that the
>
following must hold:
>
>
[dict setObject:b forKey:a];
>
b == [dict objectForKey:a];
>
>
NSDictionary does not obey this invariant. I have created a little
>
test program to make this more clear. We create an NSObject subclass
>
that faithfully implements the NSCopying protocol as documented. We
>
can use objects of this class as keys to our dictionary, but we can
>
never get the objects back out again, even using the exact same key!!
>
>
It also faithfully implements the recommendation for "hash", and yet
>
it breaks...
>
>
------------------------ dictbug.m ------------
>
#import <Foundation/Foundation.h>
>
>
@interface MyObject : NSObject <NSCopying>
>
{}
>
@end
>
@implementation MyObject
>
-copyWithZone:(NSZone*)zone
>
{
>
id copy=[[[self class] alloc] init];
>
return copy;
>
}
>
@end
>
>
int main(int argc, char *argv[] )
>
{
>
id pool=[NSAutoreleasePool new];
>
id a=[MyObject new];
>
id result=@"Hello world!";
>
id dict=[NSMutableDictionary dictionary];
>
[dict setObject:result forKey:a];
>
result = [dict objectForKey:a];
>
NSLog(@"%@",result);
>
[pool release];
>
return 0;
>
}
But your keys are not the same! Consider the docs...
- (unsigned)hash
Returns an integer that can be used as a table address in a hash table
structure. If two objects are equal (as determined by the isEqual:
method), they must have the same hash value. This last point is
particularly important if you define hash in a subclass and intend to
put instances of that subclass into a collection.
- (BOOL)isEqual:(id)anObject
Returns YES if the receiver and anObject are equal, NO otherwise. This
method defines what it means for instances to be equal. For example, a
container object might define two containers as equal if their
corresponding objects all respond YES to an isEqual: request. See the
NSData, NSDictionary, NSArray, and NSString class specifications for
examples of the use of this method.
If two objects are equal, they must have the same hash value. This last
point is particularly important if you define isEqual: in a subclass
and intend to put instances of that subclass into a collection. Make
sure you also define hash in your subclass.
.... the implementation of -hash and -isEqual: provided on NSObject
both use the id of the object-- the address of the object-- to
determine hashing and equality. As a result, the definition of
MyClass carries forward this behavior. If two different instances of
the same class are to be considered to be -isEqual: (and, therefore,
have the same -hash value), then that class must override -isEqual: and
-hash to provide said behavior. Typically, this would be accomplished
by hashing the internal state of the object, ignoring the id.
Your definition of MyClass has no internal state, therefore you could
make the above work by adding something like the following:
- (unsigned) hash { return 12345; }
- (BOOL)isEqual:(id)anObject
{
if (self == anObject) return YES;
if (!anObject) return NO;
if (([self class] == [anObject class]) && ([self hash] == [anObject
hash])) return YES;
return NO;
}
Given that NSObject's implementaton of -hash and -isEqual: cannot
possibly know anything about your subclass's internal state, the
default implementation is simplistic, but highly predictable.
b.bum
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.
References: | |
| >Ugly bug in Foundation, beware! (From: Ondra Cada <email@hidden>) |
| >Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: Alastair Houghton <email@hidden>) |
| >Re: Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: Ondra Cada <email@hidden>) |
| >Re: Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: Alastair Houghton <email@hidden>) |
| >Re: Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: Brent Gulanowski <email@hidden>) |
| >Re: Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: Alastair Houghton <email@hidden>) |
| >Re: Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: Ondra Cada <email@hidden>) |
| >Re: Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: Marcel Weiher <email@hidden>) |
| >Re: Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: Brent Gulanowski <email@hidden>) |
| >Re: Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: "Louis C. Sacha" <email@hidden>) |
| >Re: Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: Marcel Weiher <email@hidden>) |
| >Re: Is that really a bug at all? (was: Re: Ugly bug in Foundation, beware!) (From: Nat! <email@hidden>) |
| >Re: NSDictionary design bug (was: Re: Ugly bug in Foundation, beware!) (From: Marcel Weiher <email@hidden>) |