Saturday 17 January 2015

Ruby2 :Private v/s Protected Methods

Recently someone asked me the difference between private method and protected methods in Ruby.  It was then, that it dawned me that though I have used private methods a lot many times in Ruby, I have never used protected methods. What's more, I was not even quite sure on the difference between the two in Ruby context. So I decided to dig into it and here is my little post on what I understood with examples :)

Private methods in Ruby:

If a method is private in Ruby, then it cannot be called by an explicit receiver (object). It can only be call implicitly. It can be called implicitly by the class in which it has been described in as well as by the subclasses of this class.
The following examples will illustrate it better:
1) A Animal class with private method class_name
class Animal
  def intro_animal
    class_name
  end
  private
  def class_name
    "I am a #{self.class}"
  end
end
In this case:
n = Animal.new
n.intro_animal #=>I am a Animal
n.class_name #=>private method `class_name' called
2) A subclass of Animal called Amphibian:
class Amphibian << Animal
  def intro_amphibian
    class_name
  end 
end 
In this case:
  n= Amphibian.new
  n.intro_amphibian #=>I am a Amphibian
  n.class_name #=>private method `class_name' called
As you can see, private methods can be called only implicitly. They cannot be called by explicit receivers. For the same reason, private methods cannot be called outside the hirearchy of the defining class.

Protected Methods in Ruby:

If a method is protected in Ruby, then it can be called implicitly by both the defining class and its subclasses. Additionally they can also be called by an explicit receiver as long as the receiver is self or of same class as that of self:
1) A Animal class with proteced method protect_me
class Animal
  def animal_call
    protect_me
  end
  protected
  def protect_me
    p "protect_me called from #{self.class}"
  end  
end
In this case:
n= Animal.new
n.animal_call #=> protect_me called from Animal
n.protect_me #=>protected method `protect_me' called
2) A mammal class which is inherited from animal class
class Mammal < Animal
  def mammal_call
    protect_me
  end
end 
In this case
n= Mammal.new
n.mammal_call #=> protect_me called from Mammal
3) A amphibian class inherited from Animal class (same as mammal class)
class Amphibian < Animal
  def amphi_call
    Mammal.new.protect_me #Receiver same as self
    self.protect_me  #Receiver is self
  end   
end
In this case
n= Amphibian.new
n.amphi_call #=> protect_me called from Mammal
             #=> protect_me called from Amphibian  
4) A class called Tree
class Tree
  def tree_call
    Mammal.new.protect_me #Receiver is not same as self
  end
end
In this case:
n= Tree.new
n.tree_call #=>protected method `protect_me' called for #<Mammal:0x13410c0>