Understanding The Self

Alex Rios
4 min readOct 27, 2020

--

For many aspiring programmers the concept of self can become quite confusing. You’ve just learned how to create a class in Ruby and got comfortable playing with object instances. Next, the textbook instructs you to add a line containing the self keyword somewhere on your code. You run the console and appreciate its magic. To your surprise, the code runs smoothly with no error messages. When you type ClassName.all on the console you get a list of objects pertaining to that particular ClassName. But…what on Earth is going on?! How does this work? Let’s explore in detail.

In Ruby, each newly created instance of a class is considered an object. An object is composed of both attributes and behaviors. To visualize, we could create a Fruit class like this:

A new instance of Fruit can be created like this:

If we wanted to access the name of our fruit, we could type:

Now, another useful tidbit of Ruby programming is that all objects contain a sense of awareness. To be specific, every object is aware of itself.

Let’s write a method in our Fruit class that will show us the self:

If we go back to our fruit and tell it show itself, this is the result:

As we can see, the apple object is showing us that it is indeed an object instance of the class Fruit.

What does this mean?
It means that it’s possible for individual objects to enact behaviors on themselves and not just in isolation.

Let’s demonstrate this idea by writing another method in our Fruit class that would allow an instance to change its name:

The method in action:

Great! We successfully manipulated an instance’s attribute by using self!

Now, let’s build something interesting.

Let’s say that we want to access all the Fruit instances that we ever created. How can this be achieved?

Just as we were able to manipulate data using the self, it is also possible for us to use self to keep track of our object instances! We can do this with the help of an array.

Let’s introduce a class variable @@all and set it as an empty array.

Our goal is to place the class variable under the initialize method such that it can collect all the object instances the moment they are created. This is done so like this:

We’re almost done!

Let’s create a couple of fruit instances to test out our implementation:

A note of caution.
If we run our program like this, our program will indeed work. It will create all the fruit instances and save them in an array… But when we type Fruit.all in the console, the following error happens:

What gives?!

This is because as it stands, Ruby understands that we’re storing data in a class variable, but it doesn’t have explicit methods to access such data.

To accomplish our goal we need to resort again to the power of the self. As you have probably read elsewhere, everything in Ruby is an object. Because of this it is possible for us to apply self at the class-level to do something like this:

In this context, Fruit class is acknowledging itself, using the class method .all to return the data we collected with the variable @@all.

So, now we can access all our delicious fruits in one single place!

Pretty cool, huh?

The main takeaways are:
1. Everything in Ruby is an object.
2. Objects in Ruby are self aware.
3. The function of the self depends on its context.

Understanding the self can pave the way to other interesting programming venues, such as the principle of Single Source of Truth, which we’ll explore on a later post.

--

--