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 self
vs. @
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 self
vs. @
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 self
vs. @
.
So, let’s take a closer look…
The decision: use self.var
or @var
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.var
calls 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 attr_reader
, attr_writer
, or attr_accessor
.
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.
For example…
class Dog
attr_reader :breed def initialize(breed)
@breed = breed
end def display_breed
puts self.breed
end
endfido = Dog.new('beagle')
fido.display_breed
In the code above, we have a class of Dog
, and we are choosing to do two things: 1.) make a new instance of Dog
, 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 display_breed
prints beagle
.
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.
C. Cleanliness/Readability
Code littered with self
can be harder to read due to the added text.
Note 1: self
is not required for getter methods. In the example of fido
, the display_breed
method could have been written as:
def display_breed
puts breed
end
Note 2: 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.
D. Performance
@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 self
or @
? What is your preference?