- We all know and love
nil
, but what is it and how does it work? - How is
nil
different fromNULL
? - 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.