DEV Community

fentybit
fentybit

Posted on • Updated on

Ruby: Self

I am a fellow SE student at Flatiron School, and have decided to blog my coding journey. I am a novice programmer with an intense level of curiosity to learn, and always welcome any constructive criticism. Let's say - I am Baby Yoda in training, and incessantly developing my Jedi mindset.

baby_yoda

The past three weeks, I have immersed myself in Ruby procedural programming concepts from variable and methods to data structures. We proceeded with Object-Oriented Programming (OOP). The whole week, I was struggling to grasp the use of @, @@ and self. After countless hours of irb-ing, I am more comfortable now constructing Classes and implementing @, @@ and self in Object Relationships.

Okay, we understand Class is essentially a blueprint or factory. It births instances with shared attributes and behaviors. I will be using plant to iterate my thoughts as an extension of my side interest in nurseries.

class Plant 
   def name=(name)
      @name = name
   end

   def name
      @name
   end
end 

cactus = Plant.new("Cactus")
cactus.name = "Cactus"
Enter fullscreen mode Exit fullscreen mode

This is my preliminary Class scope with basic reader and getter methods. "Cactus" would be an instance of Plant class.

What is @ and @@?
@ is an instance variable, and @@ is a class variable. They are capable of traversing through instance and class methods. I call this an upgraded version of local variable. Let's refine our Plant class.

class Plant 
   @@all = []

   def name=(name)
      @name = name
   end

   def name
      @name
   end

   def save 
      @@all << self 
   end 

   def self.all 
      @@all 
   end 

   def self.chatty_plant
      self.all.each do |plant|
         puts "I am #{@name}. Water me please!"
      end 
   end  
end 
Enter fullscreen mode Exit fullscreen mode

In my earlier approach to Ruby classes, I would simply refer to @instance_variable and @@class_variable on instance and class methods. They worked, and I passed the test. As I progressed through more complex schemes, this mental modeling approach became less intuitive. What if we rename @@class_variable to @@something_else? We would have to rename every single @@class_variable. What if I misspelled @instance_variable as @instance_varyable? Would Ruby help us to catch this mistake?

The rise of self
I believe this is when we should utilize self, and construct our Ruby Classes more intuitively. Referring to @ and @@ is a literal approach, and utilizing self allows our object to operate inherently. Self refers to main, or itself, in which program functions. In instance method, self refers to the instance itself, and in class method, self refers to the class itself. Let's take a look at our first alternative approach below:

   def save 
      @@all << self 
   end 
Enter fullscreen mode Exit fullscreen mode
   def save 
      self.class.all << self 
   end 
Enter fullscreen mode Exit fullscreen mode

We can refactor @@all to self.class.all.
@@all == @@all
Plant.class == @@all
self.class.all == @@all

Why are we using self.class.all in lieu of @@all?
It is prudent to reify and refactor our instance or class methods as our code gradually becomes more complex. By using self.class.all, we avoid possible error syntax when renaming any class variables.

   def self.chatty_plant
      self.all.each do |plant|
         puts "I am #{@name}. Water me please!"
      end 
   end  
Enter fullscreen mode Exit fullscreen mode
   def self.chatty_plant
      all.each do |plant|
         puts "I am #{name}. Water me please!"
      end 
   end  
Enter fullscreen mode Exit fullscreen mode

Do we need self in self.all.each do?
self.chatty_plant is a class method, and self.all is also a class method. We can omit self in self.all.each do. Ruby understands self as an implicit receiver in this class method.

#{@name} vs. #{name}
If we erroneously typed #{@naame}, Ruby will look for an instance variable @naame which is non-existent.

#=> I am  . Water me please!
Enter fullscreen mode Exit fullscreen mode

A better approach in Ruby is to call out an instance method. If we have a typo such as #{naame} instead of #{name}, Ruby will help us to navigate the error.

#=> NameError (undefined local variable or method 'naame'..)
Enter fullscreen mode Exit fullscreen mode

This self mental modeling allows better design approach as our code gets more complex attributes and behaviors in Ruby implementation.

class Plant 
   @@all = []

   def name=(name)
      @name = name
   end

   def name
      @name
   end

   def save 
      self.class.all << self 
   end 

   def self.all 
      @@all 
   end 

   def self.chatty_plant
      all.each do |plant|
         puts "I am #{name}. Water me please!"
      end 
   end  
end 
Enter fullscreen mode Exit fullscreen mode

Keep Calm and Code On.



fentybit | GitHub | Twitter | LinkedIn

Discussion (0)