Structure and Interpretation of Computer Programmers

I make it easier and faster for you to write high-quality software.

Tuesday, May 25, 2010

On NSNull as an anti-pattern

All this talk about type-safe collections may leave you thinking: but what about NSNull? Let’s say you have an array that only accepts objects conforming to MyProtocol. You can’t add +[NSNull null] to it, because it doesn’t implement the protocol. So haven’t I just broken mutable arrays?

Let’s be clear: NSNull is a nasty hack. The original inventors of Foundation wanted to provide a variadic initialiser and factory for collection classes, but rather than doing +[NSArray arrayWithCount: (unsigned)count objects: (id)firstObject, ...] they created +[NSArray arrayWithObjects: (id)firstObject, ...]. That meant they needed a special value to flag the end of the list, and they chose nil. That meant you couldn’t put nil into an array, because such an array could not be constructed using the +arrayWithObjects: style. Therefore they decided to provide a new “nothing” placeholder, and created NSNull.

NSNull makes client code warty. If you were permitted to put nil into a collection, you could just do this:

for (id <MyProtocol>foo in myFoos) {
  [foo doSomethingInteresting];

but if you use NSNull, you get to write this (or a close variant):

for (id <MyProtocol>foo in myFoos) {
  if ([foo conformsToProtocol: @protocol(MyProtocol)]) {
    [foo doSomethingInteresting];

Nasty. You’ve actually got to perform the test that the protocol conformance is supposed to address, or something that gets you the same outcome.

I’d prefer to use a different pattern, common in languages where nil or its equivalent cannot be messaged, known as the Null Object Pattern. To be clear, all you do is implement a class that conforms to the protocol (or extends the superclass, if that’s what you’re up to) but doesn’t do anything interesting. If it’s interrogated for data, it just returns 0, NO or whatever is relevant. If it’s asked to do work, it just returns. In short, it can be used in the same way as a real instance but does nothing, just as a placeholder ought to behave. So we might do this:

@interface NullMyProtocolConformer: NSObject <MyProtocol> { }

@implementation NullMyProtocolConformer

- (void)doSomethingInteresting { }


Now we can go back to the first version of our loop iteration, and keep our type-conformance tests in our collection classes. Anywhere you might want to put NSNull, you just stuff an instance of NullMyProtocolConformer.

posted by Graham at 13:43  


  1. The preferred pattern in question is nore commonly known as “the Null Object pattern” than just “the Null pattern”:

    Comment by Kevlin Henney — 2010-05-25 @ 13:49

  2. Thanks Kevlin, I’ve updated the post to reflect that.

    Comment by Graham — 2010-05-25 @ 13:53

  3. Objective-C already does nothing on nil, it’s just NSNull that behaves badly. An easier solution is to make a helper function/macro that converts [NSNull null] into nil.

    #define NOTNULL(__x__) ((__x__) != [NSNull null] ?: nil)

    for (id foo in myFoos) {
    [NOTNULL(foo) doSomethingInteresting];

    Comment by mdhughes — 2010-05-25 @ 23:39

  4. Would it be possible to implement the null object pattern be adding a category to NSNull which handles message forwarding?

    Comment by Benedict Cohen — 2010-05-26 @ 13:01

  5. @mdhughes: that’s a nice succinct way to write the test.

    @Benedict: not in a straightforward fashion. If you take the example of type safe collections, then a null object that behaved just like nil could not be used. It would answer NO to any -conformsToProtocol: or -isKindOfClass: tests so would raise exceptions on being inserted into the collection. What you’d need is some kind of generic Null Object generator, so you could create NSNull <NSCopying> or NSNull : NSString, for instance. The ObjC language doesn’t support that.

    Comment by Graham — 2010-06-09 @ 12:17

  6. Actually, doesn’t NSNull date back to EONull from EOF in the mid-90s? The need for that would be to represent NULLs brought back from the database as objects, and they needed them to be smarter than just nil pointers.

    Comment by Jon H — 2010-06-17 @ 20:52

  7. Jon, I don’t know which versions of EOF you’ve used, so sorry if I’m teaching you to suck eggs. In EOF 2.0, the behaviour of the framework was changed so that NULL in the database was seen as nil by EOF clients. This was specifically to avoid the issue I’ve described with NSNull – users of EOF 1.x had to write explicit tests for [EONull null] in their client code.

    Comment by Graham — 2010-07-09 @ 15:13

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress