I'd argue this is the way most methods are naturally written, so it doesn't have too much of an impact.
I'm struggling to think of an example where logically returning true for a nil receiver is a much more natural than the other way around. Most of them, including your example of isEqualToString vs. isDifferenceFromString, are at best equal.
It's probably something that should be made more explicit in discussions about nil swallowing, such as the OP.
I always check for nil explicitly, personally. It sidesteps any question of whether the method makes sense in the nil case. And sending messages to nil can't work in general, because the return value could be a struct.
I agree there isn't really a sensible answer for [nil isEmpty].
There are two uses of isEmpty I can think of.
if ([container isEmpty]) {
[container addItem:item];
}
We want to add an item to an empty container. If it's nil, we don't add an item to it; that seems okay. if (![container isEmpty]) {
Item item = [container getItemAt:0];
[item doSomething];
}
We check there will be an item before we get a value out of it. This one would cause issues.NSArray doesn't have an isEmpty method. I wonder if this is one of the reasons why, or if it's just something like wanting to keep the interface small.
[Edit] You can of course invert the logic. Using [container hasItems] in the two examples above would function just fine. While isEmpty seems to be the variant used everywhere, hasItems doesn't seem too unnatural.
As for how you'd use it, I've pretty much always used it for early outs:
if(items.empty()) return NULL;
return &items[items.size()%rand()];
or for filling in caches: if(items.empty()) return NULL;
if(cache.empty()) { /* fill cache */ }
assert(cache[index].underlying_item==items[index]);
return cache[index].some_other_data;
So it always ends up being tested positively. Or it does if you code like me, anyway :) (I make no statement about whether you should or not.)I can't think of a compare method in the Objective-C core lib (the biggest nil-swallowing lib I know of). Does anyone know of one? Would be interesting to see how it's handled and if it causes issues.
You could return an enum, which would allow you to use non-obvious values (Lower = 1, Equal = 2, Higher = 3), though this would make it a bit of a pain to interface with C-style libs.
Obviously the presence of a work-around doesn't mean nil-swallowing is a good idea, but rather cements the idea that library authors need to put in extra effort to make sure nil receivers are handled appropriately.
Maybe I misunderstood you, but there is plenty of compare:'s in Cocoa: http://cl.ly/image/1a112f1B1W1g.
They all return an enum that's either -1, 0 or 1.
Also, nils aren't allowed in the collection classes, so sorting with compare: will simply never encounter this case.
if (![missleLauncher isDisabled]) { /* declare thermonuclear war */ }
When missleLauncher is nil, thermonuclear war is still declared which may not be the programmer's intent.
In Objective-C, the question "should I name my method isEnabled or isDisabled?" has a reasonable answer - you consider what makes most sense (or any sense) when called on Nil.
This is probably a good rule for other languages too - "negative" booleans can lead to double-negatives and unreadable code.
I'm not saying the example is correct, I'm pointing out that "I've never heard of it" / "Works on my computer" are dangerous attitudes to have.
Of course, there is one place where you have to go the other way: -isNil: does not work, you need to use -isNotNil
Unless you use the runtime's (private) nil-hook:
+(void)setNilHandler
{
installed=YES;
_objc_setNilReceiver([self nsNil]);
}
Then you can send messages to nil and they will be sent to your class. Of course, you want to mimic the nil-eating behavior as much as possible, so: static id idresult( id receiver, SEL selector, ... ) { return nil; }
+(BOOL)resolveInstanceMethod:(SEL)selector
{
class_addMethod(self, selector, (IMP)idresult , "@@:@");
return YES;
}