CSC/ECE 517 Fall 2007/wiki1 4 01
Ruby's access control has three levels: public
, protected
and private
. The usage of public and protected access levels are the same as that of C++ and Java, but the private level is different. In Java or C++, it is perfectly legal to invoke private methods of another object of the same class as long as the invocation took place within the class definition.
Take the following Java code for example:
public class Person { private double age; private double getAge() { return this.age; } public boolean isOlder( Person p ) { return ( this.age > p.getAge() ) ? true : false; } }
In the above code, we assume the member variable age
of the class Person
is sensitive and no accessor function of this variable should be provided. The method isOlder
takes a Person
object as a parameter. It compares the age of the current object to the age of the object p
passed in. Then isOlder
invokes p's private method getAge
to make the comparison. This invocation would be valid because it is from within the class definition. However, we can simply substitute p.getAge()
with p.age
due to the exactly same reason.
In Ruby, invoking private methods on another object is forbidden, even if that object of of the same class as the current object. The private methods can only be invoked on the current object of the class.
class Person private def getAge return age; end def too_old( other_oject ) ( getAge > 30 ) ? true : false # correct ( self.getAge > 30 ) ? true : false '''Bold text'''# ERROR! ( other_object.getAge > 30 ) ? true : false # ERROR! end end
In the above code, getAge
is defined as a private method. self and other_object are the "receivers" of that method. However, in Ruby receiver of a private method is always implicit, in other words, receiver in this case is always "self" but cannot be explicitly written out (i.e. self.getAge is not allowed). Of course, explicit invocation of a private method on another object is banned, even if it is of the same class as the current object and the invocation takes place within the class definition. In both cases, a "NoMethodError" exception would be raised.
In object-oriented languages, the private modifer is used as a mechanism to keep the private information of an object(i.e. its member variables) from being accessed by other parties. In our point of view, the only time that a method would want to call some other object's private method is to obtain the object's relevant information implicitly or explicitly. Otherwise, either the current object can simply invoke its own private method to perform the same functionality or that private method can be as well made public (i.e. there is no sensitive information needs to be protected). If indeed the private method provides some kind of access to the values of private member variables, an accessor function would be a much more elegant and maintainable solution. An accessor has a more descriptive method name and is therefore more readable. Even if in some cases, due to privacy reasons we do not want to provide accessors at all, the methods within the class definition can directly use another object's private member variables if needed, instead of having to invoke its private method to achieve the same purpose.
Therefore, considering the event of "invoking private methods of another object" rare and redundant in Java and C++, it is wise for Ruby to get rid of this capability all at once by enforcing the the receiver of a private method call to be implicit.