Self vs @: its a decision, not a rule.
As a new programming student, I grasp for black and white rules to follow when learning a new concept, and the case of
@ was no different. It was not clear when I should use
self and when I should use
@ to access instance variables. I researched in books and online, looking for a rule that would eliminate my confusion. Instead of finding one answer, I found a whole variety. Unfortunately, for the beginner in me at this stage, it seems there is no straight answer to this question.
What I realized, however, is
@ is a question and a decision I will face every time I write a custom class and/or instance method in object oriented programming. This fact points to a subtler side of problem solving that web development requires and illuminates a next level of sorts in my learning: designing code. If level one is you can find a solution to the problem, this next level is you can find multiple solutions from which you’ll pick the best option. Designing code is understanding the decisions you face as you program and knowing the advantages and disadvantages of your options. This is what is required when faced with the situation of
So, let’s take a closer look…
The decision: use
First, understand the fundamental difference: the former calls a method that returns the instance variable, and the latter does not — it is the instance variable.
What can be confusing is that
self.var appears to be calling
self.instance_var because it happens to share the same name as the
instance_var. In actuality, however,
self.a_method. In the scenario of accessing an instance variable,
a_method is the getter or setter method. In order to use
self, these getter and/or setter methods need to exist either explicitly with a method you write or implicitly with
Its easy to skip over the word ‘self’ altogether and just know that it is necessary in the same way ‘@’ is necessary to indicate an instance variable.
self, however, is actually doing a little more.
self references the object.
@breed = breed
fido = Dog.new('beagle')
In the code above, we have a class of
Dog, and we are choosing to do two things: 1.) make a new instance of
fido = Dog.new('beagle') and 2.) call the
display_breed method on
fido. When we do #1,
fido (as well as any instance of Dog) is initialized with an instance variable
@breed whose value is passed in as an argument. When we do #2, the
display_breed method prints
self.breed. What is
self.breed though? Here
self refers to the object
fido, which calls the implicit breed getter method. This getter method holds the value of
@breed: ‘beagle’. So
Secondly, consider the trade-offs of each option:
A. Private vs. Public
self.var is public, and therefore can be accessed outside the class. Depending on the circumstance, this public state could cause problems because the data is no longer protected. Note: one exception is if the getter and setter methods are explicitly made private with the ‘private’ keyword. In this case, these methods cannot be accessed outside the class.
@var is private, and therefore cannot be accessed outside the class. Obviously, this private state puts limitations on the code, which is a key concept in object oriented programming.
B. Maintenance/Encapsulation/Custom logic
self can actually be used on any instance method not just the accessor methods. One advantage to using
self is any custom logic pertaining to an instance variable is easier to maintain as the code is written in one place.
Writing this custom logic with
@var would require you to make changes in many places in your code when a revision is required at a later time.
Code littered with
self can be harder to read due to the added text.
self is not required for getter methods. In the example of
display_breed method could have been written as:
self is required for calling setter methods. Without self, the syntax of assigning a value to the instance variable via the setter method is the same as the syntax of assigning a value to a local variable
method_or_var = value, and Ruby would interpret the value as a local variable instead.
@var is faster.
Lastly, decide what is the most important factor to accommodate in your code. Over time, a developer might consistently choose one factor as more important than others, and this becomes his/her preference.
Which factors do you deem as most important to consider when deciding to use
@? What is your preference?