Objective-C's nil is the Best

Some people freak out when they find out that Objective-C's nil silently accepts any message. They may want write Objective-C as if it is C++:

- (Book *)findBookWithTitle:(NSString *)title inBooks:(NSArray *)books {
    if (title == nil || books == nil) {
        return nil;
    }

    for (Book *book in books) {
        if (book.title == nil) {
            continue;
        }

        if ([book.title isEqual:title]) {
            return book;
        }
    }

    return nil;
}

But I say you should embrace the easy-going nil. Everything is easier when messages to nil return nil no matter what. Checks for nil don't make code more safe: they're clutter. This version of the previous example is equivalent:

- (Book *)findBookWithTitle:(NSString *)title inBooks:(NSArray *)books {
    for (Book *book in books) {             // when "books" is nil it acts like an empty array
        if ([book.title isEqual:title]) {   // either title being nil makes the expression false
            return book;
        }
    }

    return nil;
}

nil is a valid value for any object. nil is your friend. nil is false.

- (BOOL)isEqual:(id)other {
    if (other == nil) {
        return NO;
    }

    if (![other isKindOfClass:[self class]]) {
        return NO;
    }

    Book *otherBook = (Book *)other;

    if (self.title == otherBook.title) {
        return YES;
    }

    if (self.title == nil || otherBook.title == nil) {
        return NO;
    }

    return [self.title isEqual:otherBook.title];
}

It's amazing what such a good definition of nil lets you get away with.

Imagine if I had to check whether the applications' settings had been initialized, whether the library had been initialized, whether the book dictionary had been initialized, and whether the book existed, just to be sure this code would never crash:

- (Book *)bookForBookId:(NSString *)bookId {
    return [[[AppDelegate.settings.library.bookDict objectForKey:bookId] retain] autorelease];
}

Easy-going nil does make it harder to track down certain errors, but it saves me so much time that I miss it in nearly every other language.

nil, you're the best.

Caveat

nil is not a friend to C structs because nil is the size of a pointer. If a method is meant to return a struct which is larger than a pointer, and you invoke the method on nil, it will return only nil—most of your struct will be garbage. (Or at least, I'm fairly certain this was true. Perhaps it was fixed in Objective-C 2.0?)

Did I level up with this post?


Comments

Click here to view the comments on this post, or just send me an e-mail.