On Feb 19, 2011, at 10:31 PM, Ken Thomases wrote:
> On Feb 19, 2011, at 9:26 PM, Quincey Morris wrote:
>
>> On Feb 19, 2011, at 19:06, Kyle Sluder wrote:
>>
>>> Your experience indicates that -containsObject: uses pointer identity,
>>> whereas -member: uses -isEqual:.
>>
>> What's especially confusing is that -[NSArray containsObject:] is documented
>> to use -isEqual. It seems like the NSSet method ought to be called
>> -containsObjectIdenticalTo: for consistency (and now clarity) reasons.
>
> I think Kyle was just mistaken about this, lead astray by Michael's claims.
> Andy's experiment shows that -[NSSet containsObject:] relies on equality, not
> identity, just as one expects. It's just that Michael has two truly
> non-equal NSNumber objects, as his gdb output showed.
BTW I was technically mistaken about my code's output. You get the *same*
instance when you do [NSNumber numberWithLongLong:1] twice, because NSNumber
happens to cache instances for low integer values. But I was correct in
principle: substitute 123456789 for 1 and everything I said becomes true.
One thing I'm puzzled about is that NSSet does not copy its entries the way
NSDictionary copies its keys. This is implied by the member: documentation
quoted earlier:
"If the set contains an object equal to object (as determined by isEqual:) then
that object (***typically this will be object***), otherwise nil."
A quick experiment confirms that elements are not copied, which leads to the
risk that NSDictionary avoids. If elements of the set happen to be mutable, one
element could mutate in such a way as to be isEqual: to another. This can be
demonstrated actually happening:
NSMutableString *s1 = [NSMutableString stringWithString:@"abc"];
NSMutableString *s2 = [NSMutableString stringWithString:@"abc"];
NSMutableString *s3 = [NSMutableString stringWithString:@"def"];
NSSet *stringSet = [NSSet setWithObjects:s1, s2, s3, nil];
NSLog(@"+++ s1 [%@] %p, hash = %ld, set contains s1? %d", s1, s1, [s1
hash], [stringSet containsObject:s1]);
NSLog(@"+++ s2 [%@] %p, hash = %ld, set contains s2? %d", s2, s2, [s2
hash], [stringSet containsObject:s2]);
NSLog(@"+++ s3 [%@] %p, hash = %ld, set contains s3? %d", s3, s3, [s3
hash], [stringSet containsObject:s3]);
NSLog(@"+++ elements BEFORE mutate:");
for (id obj in stringSet)
{
NSLog(@"+++ %p is [%@]", obj, obj);
}
[s3 setString:@"abc"]; // Mutate one set element to be equal to
another.
NSLog(@"+++ count after mutate = %d", [stringSet count]);
NSLog(@"+++ elements AFTER mutate:");
for (id obj in stringSet)
{
NSLog(@"+++ %p is [%@] -- is eq to @\"abc\"? %d", obj, obj,
[obj isEqual:@"abc"]);
}
Output:
2011-02-20 00:47:19.305 Scratcho[20333:a0f] +++ s1 [abc] 0x12b170, hash =
516202353, set contains s1? 1
2011-02-20 00:47:19.309 Scratcho[20333:a0f] +++ s2 [abc] 0x12b1b0, hash =
516202353, set contains s2? 1
2011-02-20 00:47:19.310 Scratcho[20333:a0f] +++ s3 [def] 0x12b1f0, hash =
517992642, set contains s3? 1
2011-02-20 00:47:19.310 Scratcho[20333:a0f] +++ elements BEFORE mutate:
2011-02-20 00:47:19.311 Scratcho[20333:a0f] +++ 0x12b170 is [abc]
2011-02-20 00:47:19.313 Scratcho[20333:a0f] +++ 0x12b1f0 is [def]
2011-02-20 00:47:19.313 Scratcho[20333:a0f] +++ count after mutate = 2
2011-02-20 00:47:19.314 Scratcho[20333:a0f] +++ elements AFTER mutate:
2011-02-20 00:47:19.315 Scratcho[20333:a0f] +++ 0x12b170 is [abc] -- is eq
to @"abc"? 1
2011-02-20 00:47:19.315 Scratcho[20333:a0f] +++ 0x12b1f0 is [abc] -- is eq
to @"abc"? 1
Am I missing something? Is this a known loophole in the semantics of NSSet? Is
it a deliberate compromise, which trades the performance gained by not copying
elements for a risk that almost never matters in practice?
--Andy
_______________________________________________
Cocoa-dev mailing list ([email protected])
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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]