Do you know your`self`?

Jinook Jung
Level Up Coding
Published in
4 min readFeb 4, 2021

--

Photo by Annie Spratt on Unsplash

It is hard to know well about yourself, not just in philosophy, but also in programming. I found it real while I was doing my Ruby CLI app project. Here’s how that happened.

My app is a simple introducer of any country of a user’s choice. To accomplish this goal I have 2 model classes and 2 scraper classes:

country.rb & weather.rb for 2 model classes // country_api_scraper.rb & weather_scrape.rb for 2 scraper classes

From the API data plus scraping data, my Country class gets country information to create instances. Not to get the same data from the API and scraping repeatedly, I want to save any new Country instance into a class variable called @@all. Here is what I did first:

 1| class Country
2| @@all = [] # Set class variable to collect the instances
3| def self.all # Get @@all value
4| @@all
5| end
6|
7| def initialize(hash) # Initialize a new instance from hash
8| hash.each {|k, v|
9| self.class.attr_accessor(k) # Create getters and setters
10| self.send("#{k}=", v) # Set value for created variable
11| }
12| self.all.push(self)
13| end
14| end

But, this throws an error:

undefined method ‘all’ !!!

Did you find the problem? The answer is in line 12: self.all.push(self). Hmm… Why, though? Because I forgot what myself is.

Whenever you want to use self, you have to think of what your self is in its context. In my example, the direct context of my self in the line is the initializer method, #initialize.

Then, you have to decide what kind of method #initialize is. Is it a class method or an instance method? INSTANCE METHOD!!! So, the self here is the newly created instance of Country class. And, as you can see, there is no instance method called #all, though there is a class method, #all, a getter for the class variable @@all. That’s why the computer cannot understand self.all.

To solve the problem, you need to have the access to the class variable @@all from this class’ instance, namely, the self. How to do that? self.class will give you a return value of Country. Now, in this class level, you can use the class method #all. Yeah! Below is the result:

Thank you, Annabel~^^~
Great! The currency of Mexico is peso.

It works perfectly. Whenever you visit the same country, the app will look into the @@all array to find if the specific Country instance has been already created, with no problem at all.

One quick tip about getting an instance variable in a class. There are 2 ways to get your instance variable value: 1) by directly accessing the variable, @variable_name, and 2) by using the getter(=reader) method against the variable, self.variable_name. The difference between these two ways is that the second one requires a getter method called #variable_name in the class (of course, this is an instance method). Let’s see the example.

1| class Test
2| def initialize(value)
3| @variable_name = value
4| puts self.variable_name
5| end
6| end
undefined method ‘variable_name’, which means you have no getter method for the instance variable

The code above will not work because there is no getter called #variable_name yet. Even though the new instance of Test class has an instance variable, @variable_name, there is no getter method to that. So, the next code block will solve the problem.

### By creating a getter method ###
1| class Test
2| def initialize(value)
3| @variable_name = value
4| puts self.variable_name
5| end
6|
7| def variable_name
8| @variable_name
9| end
10| end

Or,

### By using attr_reader ###
1| class Test
2| attr_reader :variable_name
3| def initialize(value)
4| @variable_name = value
5| puts self.variable_name
6| end
7| end

Or, you can just directly access to the variable:

1| class Test
2| def initialize(value)
3| @variable_name = value
4| puts @variable_name
5| end
6| end

To test the all 3 code blocks, you can type Test.new(3) (3 as a random value), and run your ruby file:

No problem at all. All of them will successfully puts out the expected result, 3.

In conclusion, self can be useful and tricky simultaneously in any programming language, including Ruby. Therefore, let’s not forget what its context is right now! (For Ruby, using binding.pry is a very good solution to this knowledge of what yourself is. For more info of pry, visit this link.)

If you want to play around more with my Country Info CLI app, please refer to this Github repository.

--

--