The nil value in Ruby
In this article we’re going to explore the following topics:
- the
nil
value - the
NilClass
class - the
nil?
method implementation
The nil value
The nil
value is used to express the notion of a “lack of an object”.
It’s also used by the Garbage Collector
— which implements a mark-and-sweep algorithm — to decide if an object should be destroyed or not.
Unlike other languages, the nil
value isn’t used to express emptiness, false, or zero.
As everything in Ruby is an object, the nil
value refers to the non-instantiable NilClass
class.
The NilClass class
NilClass
is a built-in class provided by Ruby. This class is not instantiable.
irb> NilClass.new
NoMethodError (undefined method `new' for NilClass:Class)
When a message is sent to nil
, a hard-coded C-level “class” called rb_cNilClass
— which corresponds to the NilClass
in Ruby — is used as the receiver of the message.
Then the message will be found and sent among the instance methods of the new receiver.
So, nil
acts more like a keyword than an instance. As it is just a way to express the “lack of an object” notion.
On the other hand, the NilClass
encapsulates all the logic and is used when the receiver of a message is nil
.
Feel free to have a look to my answer on StackOverflow for further information
The nil? method
Calling nil?
helps you to determine if the receiver is an object or not
irb> "I'm an object".nil?
=> false
irb> a = nil
=> nil
irb> a.nil?
=> true
Pretty simple. isn’t it?
Let’s have a look at how this method is implemented in the Ruby source code.
Ruby is written in C. But, don’t panic, this is not a problem if you are unfamiliar with this programming language because the code that we’ll see is pretty simple
// in ruby/object.c
void InitVM_Object(void) {
...
rb_define_method(rb_mKernel, "nil?", rb_false, 0);
...
rb_define_method(rb_cNilClass, "nil?", rb_true, 0);
...
}
The function InitVM_Object(void)
is called during the Ruby VM setup. This function is in charge of setting up all the environments and classes related to the Object
class.
the rb_define_method(klass, message, function, argc)
is used to add a message to a module/class and to link this message to a C-level function.
So, the rb_define_method(rb_mKernel, “nil?”, rb_false, 0);
adds the "nil?"
message to the Kernel
module and links this message to the rb_false
function. the last argument is the number of arguments that take the method — here no argument is expected.
As the Kernel
module is included in the Object
class and the Object
class is the default parent class of any class in Ruby, then almost all the classes can handle the nil?
method.
Feel free to read the
Ruby Object Model
article if you are unfamiliar with theKernel
module.
So, let’s see how the rb_false
function is implemented
static VALUE
rb_false(VALUE obj)
{
return Qfalse;
}
The rb_false
function returns Qfalse
— which is the C-level value for Ruby false
.
This means that, by default, all the objects are not nil
.
Now let’s have a look at the implementation of NilClass#nil?
via the rb_true
function
static VALUE
rb_true(VALUE obj)
{
return Qtrue;
}
The rb_true
function returns Qtrue
— which is the C-level value for Ruby true
.
This means that the NilClass#nil?
method overrides the Kernel#nil?
method (which returns false
) to make it return true
.
This is a clever implementation that respects the OOP principle by using inheritance to specialize the NilClass
class.
Ruby Mastery
We’re currently finalizing our first online course: Ruby Mastery.
Join the list for an exclusive release alert! 🔔
Also, you can follow us on x.com as we’re very active on this platform. Indeed, we post elaborate code examples every day.
💚