Ruby’s “private”: not as Private as You Expect
Tuesday, April 24th, 2007I expect that, if a language borrows a concept from another language, and if that language even uses the same name for the concept, the concept also has the same semantics. That is not the case for “private” access control in Ruby.
In Java and C++, the sematics of the “private” access modifier for a method is: the method can only be called by methods of the class that declares the private method.
In Ruby, the semantics is (taken from the pickaxe book, page 35): private methods can be called only in the context of the current object. A bit further in the book: The difference between “protected” and “private” is fairly subtle and is different in Ruby than in most common OO languages.
Indeed, the difference is subtle, certainly for C++ and Java developers learning Ruby. As the sematics above already indicate, C++ and Java have a class focus, while Ruby has an instance focus. Private in C++ and Java means: private to the class. In Ruby, it means: private to the instance.
There is another aspect of the semantics that is important. In C++ and Java, a private method can be called on a different instance than the one executing the current method. In Ruby, private methods can only be invoked on the same instance, which is enforced syntactically: private methods can only be invoked without a receiver or with self.
Because in Ruby private methods are private to an instance, they can be invoked by methods in a subclass, illustrated by the following code snippet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Superclass private def m1() puts "Superclass.m1" end end class Subclass < Superclass public def m2() m1() puts "Subclass.m2" end end Subclass.new().m2() |
The output of the program is:
irb(main):017:0> Subclass.new().m2() Superclass.m1 Subclass.m2 => nil
Private methods can also be overridden, as shown in this code snippet:
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class Superclass private def m() puts "Superclass.m" end end class Subclass < Superclass public def m() super() puts "Subclass.m" end end Subclass.new.m() |
The output of the program is:
irb(main):017:0> Subclass.new.m() Superclass.m Subclass.m => nil
A singleton method can even override a private method of the class of the instance, as illustrated by this code snippet:
33 34 35 36 37 38 39 40 41 42 43 44 45 | class MyClass private def m() puts "MyClass.m" end end object = MyClass.new() def object.m() super() puts "object.m" end object.m() |
The output of the program is:
irb(main):013:0> object.m() MyClass.m object.m => nil
The conclusion is that Ruby has no way to make methods private in the C++ and Java sense. In my opinion, that is a good thing, because private methods are bad for reusability. But I do not believe that using the word “private” was a good choice.