What are the differences between "private", "public", and "protected methods"?
Asked Answered
M

7

43

I'm learning Ruby, and have come up to a point where I am confused.

The book I am using is talking about private, public, and protected methods, but I am still a bit confused. What are the differences between each?

Monophonic answered 27/3, 2012 at 2:54 Comment(3)
2nd Edition of the Pickaxe :) It has been great up to this point.Monophonic
Related question: https://mcmap.net/q/157216/-why-does-ruby-have-both-private-and-protected-methods/38765 and possibly other questions in the access-specifier tag.Hawes
You should change the answer.Fainthearted
V
46

Public - can be called from anywhere

Private - The method cannot be called outside class scope. The object can only send the message to itself

ex: the baker has bake method as public but break_eggs is private

Protected - You can call an object's protected methods as long as the default object self is an instance of the same class as the object whose method you're calling

ex: with n protected method, c1 can ask c2 to execute c2.n, because c1 and c2 are both instances of the same class

And last but not least:

  • Inheritance: Subclasses inherit the method-access rules of their superclass

if "class D < C", then D will exhibit the same access behaviour as instances of C

reference: http://www.amazon.com/Ruby-Rails-Techniques-Developers/dp/1932394699

Vincenza answered 5/2, 2014 at 11:51 Comment(1)
I came here asking for this: Inheritance: Subclasses inherit the method-access rules of their superclass +1Cleodell
H
33

public methods are open to everyone. As for private versus protected, I refer to "Ruby Private Methods vs. Protected Methods":

What is the difference between 'private' and 'protected' methods in Ruby? In Ruby, the primary difference between a 'private' and 'protected' method is that a private method cannot be called with an explicit receiver, while a protected method can. What is an 'explicit receiver', you ask? An explicit receiver is the object that is receiving a message. In the following example, we have a receiver ('parent') and a method ('get_name'). The 'parent' object is receiving the instruction to perform the 'get_name' method.

Handicapped answered 27/3, 2012 at 2:58 Comment(5)
This is a very good example on how to explain a simple behaviour in a complicated way with unnessecary abstract concepts like "explicit receiver". 50% of the answer are about explaining what an explicit receiver is, space that could have been used to answer the question.Kirwan
This answer did not explain what the referenced author meant by an 'explicit receiver': a receiver visible in the source code, with a dot between it and the method name. The only other possibility (in Ruby syntax, I think) is to invoke a method without a dot, whereupon Ruby comes up with a receiver by following a convention. This is known as invoking a method with an 'implicit receiver'.Plotkin
@Kirwan I respectfully disagree about this being a complicated way to explain a simple behavior. On the contrary. He summarized the main difference in a mere 15 words! Seriously—try to beat that! I've been a Rubyist for ~10 years, and I've never seen a more concise explanation for what the difference is. Personally I found this answer to be helpful—and a lot simpler (including a simpler, more elegant example) than most of the other answers presented here. The fact that the author explained clarified what an explicit receiver is for those who didn't know should not count against him.Kandykane
The following example is not available anymore. Link rot man, it sucksSullen
@Kirwan can you please post your better explanation?Rarebit
C
7

Check out "Ruby Programming/Syntax/Classes" for a detailed example and explanation.

Put simply, the differences between private, public, and protected methods are visibility of that method in the program, kinda like read-only, read and write, and near invisible.

Unlike some of the other languages, you can't completely hide a Ruby private method, you can only access private methods for your instance of object and not for any other object instance of a class.

Public, of course, is total accessibility and methods are usually defaulted to public with some exceptions.

Protected methods are accessible from objects of the same class or even children, which is not the case for a private method.

Chloropicrin answered 27/3, 2012 at 3:6 Comment(2)
Private methods are normally accessible from objects of child classes, as long as they are invoked with implicit receivers (that is, without any dot on their left side).Plotkin
Because I come from a Java background the Ruby visibility settings required some reassurance and examples for me to trust I really got it. Most links and explanations lacked the depth and examples for me to be certain I understood all aspects. The link given in this answer is easy to read, clarifies all aspects and is not too much text. I recommend it. Thanks for sharing.Platon
B
7

Let me explain Private and protected methods work a little differently in Ruby than in most other programming languages. Suppose you have a class called Foo and a subclass SubFoo . In languages like Java, SubFoo has no access to any private methods defined by Foo . As seen in the Solution, Ruby provides no way to hide a class’s methods from its sub- classes. In this way, Ruby’s private works like Java’s protected.

Suppose further that you have two instances of the Foo class, a and b. In languages like Java, a and b can call each other’s private methods. In Ruby, you need to use a protected method for that. This is the main difference between private and protected methods in Ruby.

class Foo
  private
  def pri
    'hey I am private of Foo'
  end

  protected
  def prot
    'Hey I am protected of Foo'
  end
end

Now subclass of Foo

class SubFoo < Foo
  def call_pri_of_foo
    pri
  end

  def call_prot_of_foo
    prot
  end
end

Now calling the accessors within SubFoo

 > sub_foo = SubFoo.new
 => #<SubFoo:0x00000002b56ad8> 
 > sub_foo.call_pri_of_foo
 => "hey I am private of Foo" 
 > sub_foo.call_prot_of_foo
 => "Hey I am protected of Foo"

Up to here; there seem to be no difference

next_sub_foo = SubFoo.new
 => #<SubFoo:0x00000002b1a0b0>

def next_sub_foo.access_private(child_of_sub_foo)
  child_of_sub_foo.pri
end

def next_sub_foo.access_protected(child_of_sub_foo)
  child_of_sub_foo.prot
end

Now calling the accessor

> next_sub_foo.access_private(sub_foo)
# => NoMethodError: private method `pri' called for #<SubFoo:0x00000002b56ad8>

but it can access the protected methods of its siblings

> next_sub_foo.access_protected(sub_foo)
# => "Hey I am protected of Foo"

You can also see @tenderlove's blog for more clear picture http://tenderlovemaking.com/2012/09/07/protected-methods-and-ruby-2-0.html

Basketwork answered 30/3, 2016 at 14:5 Comment(0)
A
7

The difference will be on Visibility and how they are affected by Inheritance :

Visibility :

|| Anywhere || Public can be accessed from inside and outside the class.

|| Inside the class || Both Private and Protected can only be accessed from inside the class.

The similarity between Protected and Private :

  • Both can be accessed from outside the class through a public method.

The differences between Protected and Private are :

  • Private method can not be called with a receiver (not even with #self). UNLESS ... calling a PRIVATE SETTER method. If you try to remove the receiver, Ruby will create a local variable. Self is a must in this case.

  • Protected may or may not use self.

  • Protected can access another object's protected method that comes from the same class, Private can't.

When it comes to Inheritance :

  • Private methods can only be called on subclasses implicitly (simply just the name of the method) but not explicitly (using #self).

  • Protected can be called both ways (with or without #self || implicitly or explicitly).

Example with code below :

 class Dog
  attr_accessor :name, :age

  def initialize(n, a)
    self.name = n
    self.age = a
  end

  def accessing_private
    "#{self.name} in human years is #{human_years}. This is secret!"
  end

  def accessing_protected
    "Will this work? " + a_protected_method
  end

  def eat_more_than(other) 
  # accessing other instance's protected method from the same class
    daily_diet < other.daily_diet 
    "#{name} eats more than #{other.name}"
  end

  def boy 
    gender_method("boy") # accessing private setter method
  end

  protected

  def daily_diet 
    age * 2 # the younger, the more they have to eat 
  end

  def a_protected_method
    "Yes, I'm protected!"
  end

  private

  attr_writer :gender

  def gender_method(gender)
    self.gender = gender # private setter method requires self
    "#{name} is a #{gender}"
  end

  def human_years
    age * 8
  end
end

# Create the first object of Dog
blake = Dog.new("Blake", 5)

p blake.accessing_private # "Blake in human years is 16. This is secret!"

p blake.accessing_protected # "Will this work? Yes, I'm protected!"

# Create the second object of Dog
jackson = Dog.new("Jackson", 1)

# Below, protected methods from different objects of the same type/class 
# are proven to share access
p jackson.eat_more_than(blake) # true -> "Jackson eats more than Blake"

# Below, accessing private setter method through a public method.
p blake.boy # Blake is a boy 
Alric answered 1/9, 2017 at 9:35 Comment(0)
F
2

I think breaking down an explicit receiver is what is important if your having trouble grasping the concept.

An explicit receiver is an object that is accepting a message.

 person.get_name

person is the receiver and the method "get_name" is giving instructions to the object "person" to perform the method "get_name".

class Person
    attr_accessor :first_name, :last_name 

  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
    puts "And #{phone_number}" # Private method called when initialized
  end

  private 
  def phone_number
    return "XXX-XXX-XXXX"
  end
end


p p1 = Person.new("mike", "jones")


p p1.phone_number # Not within the context of the object instance.

When a method is private, it can only be used by other methods inside the object in whose class it is defined.

Farriery answered 17/9, 2016 at 21:26 Comment(0)
I
0

Studying the information I've taken from here, I extended explanations through errors, and for my opinion, helps to understand why and how to use protected and not private.

1) Protected:

The line num 12 crash because the parameter received is from another class, the error message is clear:

v.rb:12:in `==': undefined method `sku' for "Object of another class ==> crash":String (NoMethodError)

2) Private:

If remove self from line 8 and 12, and I change protected for private, crash because in line 12, other doesn't know what sku is:

v.rb:12:in `==': private method `sku' called for #<Product:0x00000001574e68 @name="Bread", @quantity=1> (NoMethodError)

The program:

class Product
  attr_accessor :name, :quantity

  def initialize(name)
    @name = name
    @quantity = 1

    puts "The SKU is #{self.sku}"
  end

  def == (other)
    self.sku == other.sku
  end

  protected
    def sku
      name.crypt("yo")
    end
end

milk1 = Product.new("Milk")
milk2 = Product.new("Milk")
bread = Product.new("Bread")

puts milk1 == bread

puts milk1 == milk2

puts milk1 == "Object of another class ==> crash"
Isodiametric answered 25/5, 2016 at 10:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.