In this article we?re going to explore the following topics:
- the nil value
- the NilClass class
- the nil? method implementation
Before to start
I?m thrilled to share with you our latest project: Fun Facts about Ruby ? Volume 1
Please feel free to spread the word and share this post! ?
Fun Facts about Ruby ? Volume 1
Fun Facts about Ruby ? Volume 1 is a collection of cards..
www.rubycademy.com
Thank you for your time!
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 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.newNoMethodError (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 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.
In another 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 the nil? method helps you to determine if the receiver is an object or not
irb> “I’m an object”.nil? => falseirb> a = nil => nilirb> a.nil? => true
Pretty simple. isn?t it?
Let?s have a look to 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.cvoid InitVM_Object(void) { … rb_define_method(rb_mKernel, “nil?”, rb_false, 0); … rb_define_method(rb_cNilClass, “nil?”, rb_true, 0); …}
The InitVM_Object function is called during the Ruby VM setup. This function is in charge of setting up all the environment 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 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 the Kernel module.
So, let?s see how the rb_false function is implemented
static VALUErb_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 object are not nil.
Now let?s have a look to the implementation of NilClass#nil? via the rb_true function
static VALUErb_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 specialise the NilClass class.
Voil !
May I have your attention please ??
Feel free to subscribe here: www.rubycademy.com
Thank you for taking the time to read this post 🙂
Feel free to ? and share this Medium post if it has been useful for you.
Here is a link to my last medium post: The Forwardable module: Part II.