Ben Ford

benford.me

The Macro Behind Nil

  • We all know and love nil, but what is it and how does it work?
  • How is nil different from NULL?
  • What gives nil the ability to respond to messages?

(That last one was a trick question.)

The three nothings

nil is the Objective-c version of the C language macro NULL, which is used to indicate a “null pointer”.

Some claim that nil is defined as (id)0, which justifies how it respond to messages. If you look at the system headers, nil is actually defined as __DARWIN_NULL, which in Objective-C is defined as (void *)0.

So actually: nil, NULL, and (void *)0 are all the same thing.

If, like me, finding this out created a lot more questions than it answered, hold on and it will make sense momentarily.

The beginning

Both nil and NULL use the macro __DARWIN_NULL, which is defined in usr/include/sys/_types.h

When compiling Objective-C code __DARWIN_NULL is defined as (void *)0.

Excerpt from user/include/sys/_types.h

#ifdef __cplusplus
#ifdef __GNUG__
#define __DARWIN_NULL __null
#else /* ! __GNUG__ */
#ifdef __LP64__
#define __DARWIN_NULL (0L)
#else /* !__LP64__ */
#define __DARWIN_NULL 0
#endif /* __LP64__ */
#endif /* __GNUG__ */
#else /* ! __cplusplus */
#define __DARWIN_NULL ((void *)0)
#endif /* __cplusplus */

The reason for this chain of #ifdef statements is due to portability. In the C language standard, the value of NULL isn’t important, only that it will never be equal to a non-null pointer. The actual value is implementation dependent, meaning the value may change depending upon the compiler in use.

The takeaway here is that when using clang, the compiler built into XCode, nil and NULL is a zero cast to void *.

What is void *

In C, void * can be assigned to a any pointer type without an explicit cast. Objective-C programmers can think of void * as id; it serves the same purpose.

So void * is basically equivalent to id.

This is why although nil is not explicitly defined as (id)0, it may as well be.

What is the point of nil, NULL, and (void *)0

To recap: nil is a convention and is exactly identical to NULL. Both nil and NULL are a macro for (void *)0.

These three statements are identical:

id nilObject1 = nil;
id nilObject2 = NULL;
id nilObject3 = (void *)0;

The reason for the three separate values is only for convention, and they should be used in three different places.

Conventions

In C, NULL is used to represent “null pointers”. It exists to allow a programmer to make the distinction between 0 and a null pointer. In Objective-C, nil replaces NULL as the way to represent “null pointers”.

Who receives messages

Quick aside on the id type. In Objective-C, id is a reference to an object of unknown type. The compiler will allow any method called on an type id object, as long as this method has been defined previously.

The idea that nil can respond to any method call without an error is actually a feature of id, not nil.

Also, id is also like void * in that you never have to cast the r-value (e.i. value being assigned) during an assignment.

Zero effort

Ultimately, nil and NULL macros are defined as zero. They are only a convention to make code more readable.

nil is used for “null pointer” in Objective-c.

NULL is used for “null pointer” in C.

Technically you could use a plain 0 in place of either of them, but they are conventions that clearly illustrate intent.