As many of you know, I have recently become a software engineering coach for the bootcamp I attended. While going through our first module it appeared that a lot of our students had a tough time grasping the concept of
self. At first, I fumbled around with explaining it in the simplest words. This really woke me up because I pride myself on writing blog posts in simple terms that are easy for beginners to understand.
I know with great thought, I can explain things in a simple way, but on the spot, I struggle. I want to get better at this and to accomplish this, it means I need to gain a deeper understanding of the topic. So, here I am writing this lovely blog post on the concept of
self in Ruby.
Let's get started.
self is a tool that allows developers to refer to a particular object or class. Grasping the concept of
self could be difficult because the object or class that
self refers to changes. The way
self changes is reliant upon the context in which it is being called in.
There are many different contexts in which
self can appear and I am going to do my best to cover as many as I can think of. Forgive me if I leave one or two out. If you know of a few others and want to include them in the comments below to add to the discussion, please do so!
Outside of any Ruby class, method, module, etc.
self refers to the top level, which is an object called
main object exists in an empty
.rb file. Ruby is an object oriented language, so even within an empty
.rb there is an object! Pretty cool, huh?!
module, the context of
self refers to the
module. If it helps, you could think of
self in this context as just referring to the name of the
module. So, if we have a
Pet module and we called
self it would output
The context of
self in a
class is very similar to that of a
self refers to the class that it is in and can also be a substitute of the
class name itself. So, if we have a
Dog class and we called
self it would output
Seems pretty simple, right? Well, at this point, it is! It's in the next two contexts that things seem to get a little confusing.
This is where things start to get a little tricky and harder to grasp. Hopefully you have an idea of what a class method looks like. If not, it is a method that has
self. prepended to the method name. In the context of
self points to the
class itself. It does not point to the instance of a
class, but to the
class as a whole.
For a simple example, let's say we have a
class variable called
@@name and we wanted to be able to get it outside of the class. In order to accomplish this, we need a
self.name, I used
puts self to retrieve what
self is pointing to within this
class method. If you noticed, it's pointing to the
Dog class not an instance of it.
The way we call
class methods is by using the
class name, in our case it is
Dog, followed by the name of the method. So, if we called
Dog.name outside of the
class the output would be
Alright, so, let's dive in and think about this
Dog class in a broader way. Let's say a dog is having puppies. Each new puppy that is born is a new instance of the
Dog class. So if a dog has 4 puppies, there would be 4 new instances of the
Well, as great dog owners, we want to keep track of all the dogs we have by creating an
@@all variable which we'll set to an empty array. Each time that one of the puppies is born, we pass the new instance of the
Dog class that is created into this
@@all variable. This way, we have all of the dogs in one place! (I'll dive into more context on how and where this should happen later.)
If we want to return this array of all of our dogs, we must create another one of those handy
class methods to get the array.
If we called
Dog.all it would return the array of all instances of the
Dog Class that have been created, which means
self is pointing to the
class itself and not an instance of the
You know how before I mentioned we'd discuss where and how we'd add each new instance of the
Dog class to the
@@all array? Well, here we go!
In this case, we want to create an
initialize method which is called on any time a new instance of a
class is created. Our
initialize method takes a
:breed and also adds this new instance to the
@@all variable by calling
Let's pause for a second. Thinking about everything I just said, what do you think
self will refer to when called in the
If you guessed that
self points back to the new instance of the
class being created, you are correct!
To make sense of this, within the
initialize method we are setting instance variables to be used throughout the class using the parameters given. Unlike our previous example with
@@name, the name
"Buddy" will only refer to that instance of the
Dog class, as not all dogs created are named
"Buddy". If you think about it, if we are assigning these variables for this specific instance of the
class in this method then
self must be pointing to the instance of the
initialize is not our only class instance method. Any method you create within a
class which is not prepended by
self. is an instance method. This means that in any of those methods
self refers to the instance of the class it is being called on.
This is why we use
buddy.play_fetch instead of
Dog.play_fetch. We want Buddy, the black lab, to play fetch with a stranger not the
We've explored a few different contexts of
self in Ruby today. We've learned that within a blank
self refers to the
main object. We now know that within a
self refers to the
model it is in, unless of course we are calling it within an instance method in a class, in which case it points to the instance of the
class. Finally, we learned about
class methods and that they refer to the
Hopefully, if you were having trouble understanding the concept of
self, you have a better understanding of it now thanks to all the puppies.
Note: The cover image for this blog post is brought to you from the Sunflower Festival at Swank Farms in Hollister, CA.