Meet your new friend: self
When coding, it’s not always easy to know what’s what. Why can’t I call that method on this array? When in a method, what am I working with exactly? In these cases, self
can prove a super-duper friend!
Even if you’re a junior developer, you’ve probably come across self
in class methods definition.
But that usually it.
Now, self
can also come in handy when your understanding of what’s going on is a bit muddy. Let’s code something!
Say I want to recode the .map
method.
First thing I’ll do is to start by defining .my_map
and have it output something nice.
What I expect, when running this code, is to get "Hello from my_map"
.
🤔 Duh.
What does it mean by private method? Let’s output our current context (i.e. where the hell we are) with self
.
main
means that we currently are in the context of the Object object. Remember when you were told that all things in Ruby are objects? Well, even Object is an object.
Ruby top classes (or objects) are BasicObject > Kernel > Object.
BasicObject is the parent class of all classes in Ruby. Basic methods like ==
, !
, !=
, equal?
are defined there. Kernel is a module with basics public/private methods like puts
, gets
or chomp
. Object inherits from BasicObject and mixes in the Kernel module for good measure. All other Ruby objects inherit from Object. This way, Ruby objects get tons of methods, the latter being defined at the appropriate level of abstraction. Some methods from Object include: to_s
or nil?
. Fancy right?
Ok, but what about that NoMethodError
of mine?
Here’s my mistake: I’ve forgot to write .my_map
in a class. So it’s been defined in the Object object by default. And yet, I’m trying to call .my_map
on an array.
In order to call .my_map
on an array, I need to open and define it in the Array class.
👏 It works! Classes in Ruby can be opened and modified. Now that I’ve defined .my_map
inside the Array class, I can call it on arrays. Easy peasy!
A side note: If you feel like it, you can modify the real .map
and make it do weird things too.
Alright, now I want to pass the { |integer| integer * 2 }
block to .my_map
. I know I should loop through the array and yield the block at some point. But since I’m not passing the array as an argument, where am I to call .each
on it?
Let’s see what self
has to say.
When we are in .my_map
, the default value we’re working with is the array .my_map
was called upon. I now know I can call .each
on self
(i.e. [1, 2, 3]
).
First, I can read from the error message that I’m in the <class:Array>
. That’s good. Now, what about this NoMethodError: undefined method '*' for nil:NilClass
? Well, it simply says that in the NilClass 1, there are no methods *
defined 2.
It means that my block { |integer| integer * 2 }
can’t execute the multiplication because the integer
variable inside it is nil
. yield
can take arguments though. So inside the loop, I’ll just pass the current integer - i
- to yield
.
Which can be refactored like this:
🥳 Done!
self
is also pretty useful to figure out the scopes of your variables. But that’ll do for another article.
The key takeaway for today is: Next time you don’t know where the fuck you are in your code, call self
to the rescue!
Cheers,
Rémi