Ruby: Is nil?

September 11, 2010 / category: Ruby / 12 comments

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.

My eBook: “Memoirs of a Software Team Leader”
Read more »


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 reffered 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.

Comments

There are 12 comments / Submit your comment

Milan Dobrota
September 11, 2010 06:17 PM

Should be:

unless my_object.nil?
  my_object.display_info()
else
  puts "There is no object!"
end

Lukasz Wrobel
September 11, 2010 08:57 PM

Of course there was a mistake... I've already fixed it, many thanks!

Ray
September 12, 2010 02:30 AM

Why didn't you use the "unless" version?

Lukasz Wrobel
September 12, 2010 11:12 AM

Just for the sake of readability; I think that "if my_object.nil?" is much more clearer in this case. I usually use the "unless" keyword in this way:

raise NotFound unless @post

Rob
October 21, 2011 06:48 AM

Really clear and thorough explanation, thanks.

So you're saying that I should always write: if x.object_id == 4 when I want to see if x is nil, then?

Just kidding.

Matt
December 29, 2011 02:32 AM

No, this does not work.

Calling: if my_object.nil?

If my_object is null results in an error.

Lukasz Wrobel
December 29, 2011 08:43 PM

No, this does not work.

Calling: if my_object.nil?

If my_object is null results in an error.

It does work, but only for objects being potentially nil. That is, a reference has to exist.

Calling nil? on an existing variable will always work, though calling this (or any other) method on an undefined variable causes the NameError to be raised.

To achieve what you wanted to achieve, you can call defined?:

> defined? my_object
=> nil

> my_object = 1
> defined? my_object
=> "local-variable"

> my_object = nil
> defined? my_object
=> "local-variable"
> my_object.nil?
=> true

Joris
March 12, 2012 08:30 PM

Hey,

Learning Ruby right now, your article helped me out. Thanks!

poffuomo
May 05, 2012 04:33 PM

Well done, your articles are really clear and useful!

Doug
June 26, 2012 05:41 PM

This was really helpful. Thanks for taking the time to explain.

Taldar
March 12, 2013 04:52 PM

Hey, great article. Thanks for mentioning how Fixnum ids are just the left-shift-plus-one of the value they represent. That's super cool. It raises an important question for a Ruby learner like myself: are Fixnums actual objects, or are they just pseudo-objects?

Jess
March 04, 2014 05:08 PM

This ruby n00b found this article helpful. Thank you.

You can use Markdown in your comments if you wish. Examples:

*emphasis*
emphasis
**strong**
strong
`inline code`
inline code
[My blog](http://lukaszwrobel.pl)
My blog
# use 4 spaces to indent
# a block of code
    def my_method(x)
      x = x + 1
    end
def my_method(x)
  x = x + 1
end

* First.
* Second.
  • First.
  • Second.

> This is a citation.
> Even more citation.

I don't agree with you.

This is a citation. Even more citation.

I don't agree with you.


Submit your comment

(required)

(optional)

(required, Markdown supported)


Preview:

My eBook: “Memoirs of a Software Team Leader”

Read more »