Why doesn't NSOrderedSet inherit from NSSet?
Asked Answered
E

1

51

Surely an ordered set is a more-specific case of a set, so why does NSOrderedSet inherit from NSObject rather than NSSet?

Eudemon answered 1/7, 2012 at 1:41 Comment(4)
If developer.apple.com weren't down right now, I'd go take a look at the docs because now you've got me curious! Excellent question. And hopefully an Apple site won't stay down for too long, right?Hyacinthie
(Disclaimer: This is pure speculation, and too unconvincing for me to want to actually provide it as an answer, but...) An NSOrderedSet is a more-specific case of both an NSSet and an NSArray. Those are both classes not protocols, and there's no multiple inheritance in Objective-C. So, which do you pick? There's an argument for NSSet because of the name, but it could totally have been NSUniqueArray, right? Play it safe, ditch them both...Dunk
I see exactly what you're saying, but you're right that it's not all that convincing. I'd intuitively expect [aSet intersectsSet:anOrderedSet] to be possible (but it's not since the NSOrderedSet is not a subclass of NSSet), so NSSet makes a far more logical choice for a superclass than NSArray - and even if they made equally logical choices, losing the polymorphism makes choosing neither an inferior option anyway.Eudemon
Good question. I had to think hard about this one for a while.Narrowminded
N
77

I went through the interface of NSSet and you're right, ordered sets appear to satisfy the Liskov substitution principle and could therefor inherit from NSSet.

There is one little method that breaks this: mutableCopy. The return value of mutableCopy must be an NSMutableSet, but NSMutableOrderedSet should inherit from NSOrderedSet. You can't have both.

Let me explain with some code. First, let's look at the correct behaviour of NSSet and NSMutableSet:

NSSet* immutable = [NSSet set];
NSMutableSet* mutable = [immutable mutableCopy];

[mutable isKindOfClass:[NSSet class]]; // YES
[mutable isKindOfClass:[NSMutableSet class]]; // YES

Now, let's pretend NSOrderedSet inherits from NSSet, and NSMutableOrderedSet inherits from NSOrderedSet:

//Example 1
NSOrderedSet* immutable = [NSOrderedSet orderedSet];
NSMutableOrderedSet* mutable = [immutable mutableCopy];

[mutable isKindOfClass:[NSSet class]]; // YES
[mutable isKindOfClass:[NSMutableSet class]]; // NO (this is the problem)

What if NSMutableOrderedSet inherited from NSMutableSet instead? Then we get a different problem:

//Example 2
NSOrderedSet* immutable = [NSOrderedSet orderedSet];
NSMutableOrderedSet* mutable = [immutable mutableCopy];

[mutable isKindOfClass:[NSSet class]]; // YES
[mutable isKindOfClass:[NSMutableSet class]]; // YES
[mutable isKindOfClass:[NSOrderedSet class]]; // NO (this is a problem)

In Example 1, you wouldn't be able to pass an NSOrderedSet into a function expecting an NSSet because the behaviour is different. Basically, it's a backwards compatibility problem.

In Example 2, you can't pass an NSMutableOrderedSet into a function expecting an NSOrderedSet because the former doesn't inherit from the latter.

All of this is because NSMutableOrderedSet can't inherit from both NSMutableSet and NSOrderedSet because Objective-C doesn't have multiple inheritance. The way to get around this is to make protocols for NSMutableSet and NSOrderedSet, because then NSMutableOrderedSet can implement both protocols. I guess the Apple developers just though it was simpler without the extra protocols.

Narrowminded answered 1/7, 2012 at 2:48 Comment(5)
I think the protocols would make more sense - it could be more to do with the fact that the NSMutableSet was already defined and didn't already use a protocol for the mutability. Couldn't the protocol still be added despite the fact that NSMutableSet already conforms to it?Eudemon
If they wanted to, they could add a new protocol without breaking anything. We might see it added in the future.Narrowminded
Great answer, this was used in NSHipster book, which is how I found this question... do you know why the NSHipster book links this issue directly to NSSet being a class cluster?, I simply don't see how if NSSet was a concrete class that this would be any different with the mutable copy issue, do you know? nshipster.com/nsorderedsetCompetitor
@OscarGomez Oh cool, I didn't notice this in NSHipster. When they mention class clusters, I think they are specifically talking about how clusters (such as NSSet) often contain a mutable and immutable public class, which is the core of the problem. I don't think they're implying that private cluster subclasses affect the issue.Narrowminded
@TomDalling Thanks, I guess that is what he is referring to.Competitor

© 2022 - 2024 — McMap. All rights reserved.