Ruby’s “private”: not as Private as You Expect
By KoenI 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.
Share This
April 26th, 2007 at 6:50 pm
Private methods bad for reusability?
I love ruby and all, but encapsulation is actually GOOD for reusability. I wish they’d fix some of this stuff up to make it a little more sturdy.
So many things in Ruby are along the lines of “you can, but you shouldn’t”. Guess this is just one of those things…
April 26th, 2007 at 8:25 pm
Actually, data encapsulation is bad for reusability in general, yes. As a library vendor, you never know the needs of your clients, so maybe you thought out a certain way to interact with your library from the outside, but maybe you have a lot of users that need to interact with it in a different way, that you hadn’t foresaw.
So, you publish your code and your classes without all the “private” thingies, and then you publish your interfaces with the contract you designed. That just guides people along the “suggested path” for your library, but allows clients to leverage the full power of your code :)
And please, dont answer with the “we have to protect them from possible mistakes of using the code”, if you dont assume programmers are intelligent enough, then why the hell are you giving them your library, if you are so smarter than them? :P
April 27th, 2007 at 3:19 am
FYI, Ruby and Java were first developed around the same time, and both were released to the public in 1995. If the private keyword existed from the beginning, then Ruby would not have been following Java’s lead, since it’s unlikely that Matz (Ruby) or James Gosling (Java) knew much about what the other was doing. Both languages followed the release of C++.
April 27th, 2007 at 8:38 am
Actually I think data encapsulation protects the author just as much as the users of a “library”. It allows the underlying implementation to be refactored with a degree of protection.
In any event you can override the private methods dynamically for example the CSV library:
class CSV
class
April 27th, 2007 at 8:40 am
Oops I think the code example got cut off:
class CSV
class
April 27th, 2007 at 8:49 am
Ok one more try :-(
class CSV
class
April 27th, 2007 at 9:32 am
Well C@3p. This guy is way smarter than me and a good video:
http://video.google.com/videoplay?docid=-3733345136856180693