tags:

views:

84

answers:

2

Before I read this article, I thought access control in Ruby worked like this:

  • public - can be accessed by any object (e.g. Obj.new.public_method)
  • protected - can only be accessed from within the object itself, as well as any subclasses
  • private - same as protected, but the method doesn't exist in subclasses

However, it appears that protected and private act the same, except for the fact that you can't call private methods with an explicit receiver (i.e. self.protected_method works, but self.private_method doesn't).

What's the point of this? When is there a scenario when you wouldn't want your method called with an explicit receiver?

+3  A: 

protected methods can be called by any instance of the defining class or its subclasses.

private methods can be called only from within the calling object. You cannot access another instance's private methods directly.

Here is a quick practical example:

def compareTo(x)
 self.someMethod <=> x.someMethod
end

someMethod cannot be private here. It must be protected because you need it to support explicit receivers. Your typical internal helper methods can usually be private since they never need to be called like this.

It is important to note that this is different from the way java or c++ works. private in Ruby is similar to protected in Java/C++ in that subclasses have access to the method. In ruby, there is no way to restrict access to a method from its subclasses like you can with private in Java.

Visibility in Ruby is largely a "recommendation" anyways since you can always gain access to a method using send:

irb(main):001:0> class A
irb(main):002:1>   private
irb(main):003:1>   def notSoPrivateMethod
irb(main):004:2>     puts "Hello World"
irb(main):005:2>   end
irb(main):006:1> end
=> nil

irb(main):007:0> foo = A.new
=> #<A:0x31688f>

irb(main):009:0> foo.send :notSoPrivateMethod
Hello World
=> nil
dbyrne
Ah, ok that makes a lot more sense. My misunderstanding came from thinking `private` vs `protected` had to do whether a subclass could inherit a method, but it's actually about where the method can be called from.Thanks!
Kyle Slattery
+2  A: 

Consider a private method in Java. It can be called from within the same class, of course, but it can also be called by another instance of that same class:

public class Foo {

   private void myPrivateMethod() {
     //stuff
   }

   private void anotherMethod() {
       myPrivateMethod(); //calls on self, no explicit receiver
       Foo foo = new Foo();
       foo.myPrivateMethod(); //this works
   }
}

So -- if the caller is a different instance of my same class -- my private method is actually accessible from the "outside", so to speak. This actually makes it seem not all that private.

In Ruby, on the other hand, a private method really is meant to be private only to the current instance. This is what removing the option of an explicit receiver provides.

On the other hand, I should certainly point out that it's pretty common in the Ruby community to not use these visibility controls at all, given that Ruby gives you ways to get around them anyway. Unlike in the Java world, the tendency is to make everything accessible and trust other developers not to screw things up.

JacobM