• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: -[NSSet containsObject:] returns NO when it should return YES
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: -[NSSet containsObject:] returns NO when it should return YES


  • Subject: Re: -[NSSet containsObject:] returns NO when it should return YES
  • From: Andy Lee <email@hidden>
  • Date: Sun, 20 Feb 2011 00:54:45 -0500

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@hidden)

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:

This email sent to email@hidden

  • Follow-Ups:
    • Re: -[NSSet containsObject:] returns NO when it should return YES
      • From: Roland King <email@hidden>
References: 
 >-[NSSet containsObject:] returns NO when it should return YES (From: Michael Crawford <email@hidden>)
 >Re: -[NSSet containsObject:] returns NO when it should return YES (From: Ken Thomases <email@hidden>)
 >Re: -[NSSet containsObject:] returns NO when it should return YES (From: Michael Crawford <email@hidden>)
 >Re: -[NSSet containsObject:] returns NO when it should return YES (From: Kyle Sluder <email@hidden>)
 >Re: -[NSSet containsObject:] returns NO when it should return YES (From: Quincey Morris <email@hidden>)
 >Re: -[NSSet containsObject:] returns NO when it should return YES (From: Ken Thomases <email@hidden>)

  • Prev by Date: Re: Keeping Multiple Identical Tables in Synch - Weird SortDescriptor Binding Problem
  • Next by Date: Re: -[NSSet containsObject:] returns NO when it should return YES
  • Previous by thread: Re: -[NSSet containsObject:] returns NO when it should return YES
  • Next by thread: Re: -[NSSet containsObject:] returns NO when it should return YES
  • Index(es):
    • Date
    • Thread