For many beginning Rubyists, especially those having experience in other programming languages such as Java or C, checking whether variable is nil
may seem a little bit confusing. And even those speaking Ruby quite fluently don’t usually know the tiny little details that stand behind the nil
object.
NilClass and Nil Object
In Ruby, there are no primitives. I don’t mean people hunting for mammoths and living in caves, I mean primitive types. That is, there is no distinction between simple variables (like numbers) and more complicated ones. They all have one common ancestor, the Object
class. 5 is an object and hash is an object, too. Everything is an object.
Former Java or C programmers are used to treat NULL
as a special value or even a keyword. In these languages, NULL
holds a value that no valid pointer will ever refer to. So, to check whether object is nil
(NULL
), one should compare it with the special NULL
value:
// Java code
//
if (myObject != null) {
myObject.displayInfo();
} else {
System.out.println("There is no object!");
}
As you can see, programmer needs to make sure first that the object really exists, i.e. it points to something different than null
. Calling methods on a null
object causes the NullPointerException
to be thrown. In C, operating on invalid pointer may lead to unexpected results.
As you may expect, there should be a Ruby way to check if object is nil
. Here it is:
# Ruby code
#
if my_object.nil?
puts "There is no object!"
else
my_object.display_info()
end
Wait a second… What we’ve actually done to check if object is nil, was to call the nil?
method. Calling a method on a not existing object? Isn’t it any kind of trap?
No, it is not. As I’ve already said, in Ruby every value is an object. So, nil
is an object, too. In fact, it is an instance of the NilClass
:
> nil.class
=> NilClass
Moreover, nil
is always equal to nil
:
> nil == nil
=> true
Theoretically, nil
values should be incomparable, just like it is in SQL. But for practical reasons and to spare memory, nil
object was made a singleton. That is, there is always exactly one instance of the NilClass
which can be simply referred to by typing nil
.
To keep things consistent, the nil?
method has been moved to the very top of the object tree - to the Object
class. Having that in mind, you can call this method on any object you want and it will return a result rather than cause the NoMethodError
to be raised:
> 5.nil?
=> false
> [1, 2, 3].nil?
=> false
> {:a => 1}[:b].nil?
=> true
> nil.nil?
=> true
Nil and Ruby Interpreter
There’s an interesting feature concerning the nil
object implementation, which many Ruby programmers don’t even know about. Take a look:
> nil.object_id
=> 4
Let’s run the Ruby interpreter again:
> nil.object_id
=> 4
Either it’s a coincidence or something (someone) stands behind it. As you may have guessed, I wouldn’t bother you if it wasn’t something more than just blind fate. In fact, it stems from the way that Matz designed the Ruby interpreter.
Why is the object id of nil
equal to 4? First, you need to know that false
and true
variables work exactly the same way as nil
does. They are singleton instances of FalseClass
and TrueClass
, respectively. When the Ruby interpreter boots up, it initializes FalseClass
, TrueClass
and NilClass
. The result is:
> false.object_id
=> 0
> true.object_id
=> 2
> nil.object_id
=> 4
What happened to 1 and 3? Well, the first bit is reserved for Fixnum
values (numbers) only. Simple and consistent.
So, know you not only know how to check if Ruby object is nil
, but also you got to know some peculiar Ruby implementation details. I hope the article was worth reading.