Ruby Method Visibility
By: Nick Plante
Tags: Ruby, Software Development

In Java (and most OO languages), declaring a method as private means that the method can only be accessed within the context of the defining class. Similarly, protected means that the method can only be accessed from that class or any of its subclasses.

In Ruby, things are a bit different. Both private and protected methods can be called by any instance of the defining class and its subclasses. Inheritance plays absolutely no role in determining the visibility of a method. The difference instead is that private methods can never be called with an explicit receiver, even if the receiver is self . This means that it’s not possible to access another object’s private methods, even if the object is of the same type as the caller. A private method must be called from within the calling object.

Consider the following example:

class Person

def public_method

"public"

end



protected

def protected_method

"protected"

end



private

def private_method

"private"

end

end



class SalesPerson < Person

def check_protected_method_explicit_receiver

"#{self.protected_method} method OK with explicit receiver"

rescue

"failure accessing protected method with explicit receiver"

end



def check_protected_method_implicit_receiver

"#{protected_method} method OK with implicit receiver"

rescue

"failure accessing protected method with implicit receiver"

end



def check_private_method_explicit_receiver

"#{self.private_method} method OK with explicit receiver"

rescue

"failure accessing private method with explicit receiver"

end



def check_private_method_implicit_receiver

"#{private_method} method OK with implicit receiver"

rescue

"failure accessing private method with implicit receiver"

end

end

The public method can of course be accessed from anywhere (in this case, outside the class with an explicit receiver) and both private and protected methods of Person will obviously raise a NoMethodError .

Person.new.public_method

=> "public"

Person.new.private_method

=> NoMethodError: private method `private_method' called for #<Person:0x6ec698>

Person.new.protected_method

=> NoMethodError: protected method `protected_method' called for #<Person:0x6ea5c8>

So the protected method cannot be accessed outside of the class or it’s subclass, but from within the subclass, using it with either an implicit or explicit receiver works fine:

SalesPerson.new.check_protected_method_explicit_receiver

=> "protected method OK with explicit receiver"

SalesPerson.new.check_protected_method_implicit_receiver

=> "protected method OK with implicit receiver"

The private method can also be called from the subclass, but note how it only works with an implicit receiver:

SalesPerson.new.check_private_method_explicit_receiver

=> "failure accessing private method with explicit receiver"

SalesPerson.new.check_private_method_implicit_receiver

=> "private method OK with implicit receiver"

This also means you can do stuff like:

class Person

def ==(other)

protected_method == other.protected_method

end

end



x = SalesPerson.new

y = Person.new

x == y

=> true

We’re accessing the protected_method of another class instance that shares our type here, specifying an explicit receiver. If you were to try to use private_method instead, a NoMethodError would be raised. You could also just call other.send("private_method") if you really wanted to, violating our encapsulation and angering the gods of object orientation. This is only a “little sin” though, and can be permissible if the situation calls for it (like, cough cough, my latest commit to DataMapper).

In summary, method visibility and access control can be a bit confusing at first, especially if you’re coming over to Ruby from some other OO language. If you’re still confused, there’s more information available here and here. Do yourself a favor and make sure you understand, cuz it’s important stuff!