CSC/ECE 517 Fall 2007/wiki1 4 01: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
 
(22 intermediate revisions by 2 users not shown)
Line 1: Line 1:
Ruby's access control has three levels: <code>public</code>, <code>protected</code> and <code>private</code>. 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.<br>
== The Question ==
 
Ruby's private methods can be called only on "self" (the calling object). They can't be applied to other objects of the same class, even from within the class definition. In class today, I opined that it is rarely if ever necessary to call a private method on another object of the same class. Try to find Java or C++ examples on the Web where a private method is called on another object. Decide if this is good design, or if it would be better performed by using accessor functions, from the standpoint of elegance or maintainability. If you cannot find any such examples (or even if you can), try to find arguments about why one should not invoke private methods on other objects. Analyze these arguments; can you find weaknesses?
 
== Understanding the Question ==
 
In some languages such as Java and C++, it is legal to call the private methods on another object of the same class. However, in Ruby, the private methods can be called only on "self", implicitly. Did the authors of Ruby deliberately disable this functionality? If yes, why? What gain or drawback is there to nullify this feature and is it worth it?
 
== Access Control ==
 
Object-oriented programming supports three levels of access control: ''public'', ''protected'' and ''private''.
 
* '''Public''': the member variables and methods which are defined as public in a class can be called by anyone, including the object of the class and the classes inheriting from it.
* '''Protected''': the visibility of member variables and methods which are defined as protected in a class is restricted, they can only be called by the class itself, the object of the defining class and subclasses inheriting from it.
* '''Private''': the access of member varialbes and methods which are defined as private in a class is restricted only in the class itself. They can only be called by the methods which are part of the same class.
 
=== Example ===
 
Java example [3]:
 
<pre>
    public class A {
        private int x;
        protected int z;
 
        public A()
        {
            x = 10;
            z = 15;
        }
 
        public int getX() {
            return x;
        }
 
        public int getZ() {
            return z;
        }
    }
 
    public class B extends A {
        private int y;
 
        public B()
        {
            super();        // calls A constructor
            y = 20;
        }
 
        public void display()
        {
            System.out.print("X: " + getX() + " ");
            System.out.print("Y: " + y + " ");
            System.out.println("Z: " + z);
        }
</pre>
 
=== Accessor ===
 
Most of the time, member variables are labeled as private. In some case, we might need to access the values of the member variables outside of the class definition. Instead of making them public, which violates the encapsulation of OO philosophy, we can provide functions that return the values of the member variables, known as accessors. For example, in the above code segment, methods getX() and getZ() are accessors.
 
== Private Method in Ruby ==
 
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.
 
for example:
 
<pre>
class Person
  private
  def getAge
  return age;
  end
  def too_old( other_oject ) 
      ( getAge > 30 ) ? true : false             # correct
      ( self.getAge > 30 ) ? true : false          # ERROR!
      ( other_object.getAge > 30 ) ? true : false  # ERROR!
  end
end
</pre>
In the above code, <code>getAge</code> is defined as a private method. self and other_object are the "receivers" of that method. The first statement in the method is therfore legal as the receiver of the call to <code>getAge</code> is not only self but also implicit. The latter two violate this rule and errors will be raised.
 
== Compared with Java ==
 
In Java or C++, it is perfectly legal to invoke private methods of another object of the same class as long as the invocation takes place within the class definition.<br>


Take the following Java code for example:
Take the following Java code for example:
Line 6: Line 91:
{
{
     private double age;
     private double age;
       
     private double getAge()
     private double getAge()
     {
     {
Line 18: Line 102:
}
}
</pre>
</pre>
In the above code, we assume the member variable <code>age</code> of the class <code>Person</code> is sensitive and no accessor function of this variable should be provided. The method <code>isOlder</code> takes a <code>Person</code> object as a parameter. It compares the age of the current object to the age of the object <code>p</code> passed in. Then <code>isOlder</code> invokes p's private method <code>getAge</code> to make the comparison. This invocation would be valid because it is from within the class definition. However, we can simply substitute <code>p.getAge()</code> with <code>p.age</code> due to the exactly same reason.  
In the above code, we assume the member variable <code>age</code> of the class <code>Person</code> is sensitive and no accessor function of this variable should be provided. The method <code>isOlder</code> takes a <code>Person</code> object as a parameter. It compares the age of the current object to the age of the object <code>p</code> passed in. Then <code>isOlder</code> invokes p's private method <code>getAge</code> to make the comparison. This invocation would be valid because it is from within the class definition. However, we can simply substitute <code>p.getAge()</code> with <code>p.age</code> 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.
As the [http://pg.ece.ncsu.edu/mediawiki/index.php/CSC/ECE_517_Fall_2007/wiki1_4_01#Private_Method_in_Ruby Ruby code] shown above, 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 <i>"NoMethodError"</i> exception would be raised.  
<pre>
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
</pre>
In the above code, <code>getAge</code> 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 <i>"NoMethodError"</i> 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>(i.e. its member variables)</i> 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>(i.e. there is no sensitive information needs to be protected)</i>. 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.<br>
In object-oriented languages, the private modifier is used as a mechanism to keep the private information of an object<i>(i.e. its member variables)</i> 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>(i.e. there is no sensitive information needs to be protected)</i>. 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.<br>


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.
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.
== References ==
1. http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Classes#Private<br>
2. http://en.wikipedia.org/wiki/Class_%28computer_science%29#Private.2C_protected.2C_and_public<br>
3. http://www.mines.edu/Academic/courses/math_cs/macs262/INFO/Classes_in_Java_and_C++.html#Inheritance<br>
4. ''Programming Ruby: The Pragmatic Programmers' Guide (Pragmatic Programmers Series) by Dave Thomas, Andy Hunt, Andrew Hunt, Chad Fowler, Chad Fowler'' [http://www.amazon.com/Programming-Ruby-Pragmatic-Programmers-Second/dp/0974514055/ref=sr_11_1/105-8776656-7398862?ie=UTF8&qid=1190163689&sr=11-1 [4]]<br>

Latest revision as of 02:39, 19 September 2007

The Question

Ruby's private methods can be called only on "self" (the calling object). They can't be applied to other objects of the same class, even from within the class definition. In class today, I opined that it is rarely if ever necessary to call a private method on another object of the same class. Try to find Java or C++ examples on the Web where a private method is called on another object. Decide if this is good design, or if it would be better performed by using accessor functions, from the standpoint of elegance or maintainability. If you cannot find any such examples (or even if you can), try to find arguments about why one should not invoke private methods on other objects. Analyze these arguments; can you find weaknesses?

Understanding the Question

In some languages such as Java and C++, it is legal to call the private methods on another object of the same class. However, in Ruby, the private methods can be called only on "self", implicitly. Did the authors of Ruby deliberately disable this functionality? If yes, why? What gain or drawback is there to nullify this feature and is it worth it?

Access Control

Object-oriented programming supports three levels of access control: public, protected and private.

  • Public: the member variables and methods which are defined as public in a class can be called by anyone, including the object of the class and the classes inheriting from it.
  • Protected: the visibility of member variables and methods which are defined as protected in a class is restricted, they can only be called by the class itself, the object of the defining class and subclasses inheriting from it.
  • Private: the access of member varialbes and methods which are defined as private in a class is restricted only in the class itself. They can only be called by the methods which are part of the same class.

Example

Java example [3]:

    public class A {
        private int x;
        protected int z;

        public A()
        {
            x = 10;
            z = 15;
        }

        public int getX() {
            return x;
        }

        public int getZ() {
            return z;
        }
    }

    public class B extends A {
        private int y;

        public B()
        {
            super();         // calls A constructor
            y = 20;
        }

        public void display()
        {
            System.out.print("X: " + getX() + " ");
            System.out.print("Y: " + y + " ");
            System.out.println("Z: " + z);
        }

Accessor

Most of the time, member variables are labeled as private. In some case, we might need to access the values of the member variables outside of the class definition. Instead of making them public, which violates the encapsulation of OO philosophy, we can provide functions that return the values of the member variables, known as accessors. For example, in the above code segment, methods getX() and getZ() are accessors.

Private Method in Ruby

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.

for example:

class Person
   private
   def getAge
   	return age;
   end
	
   def too_old( other_oject )   
      ( getAge > 30 ) ? true : false	            # correct
      ( self.getAge > 30 ) ? true : false           # 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. The first statement in the method is therfore legal as the receiver of the call to getAge is not only self but also implicit. The latter two violate this rule and errors will be raised.

Compared with Java

In Java or C++, it is perfectly legal to invoke private methods of another object of the same class as long as the invocation takes 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.

As the Ruby code shown above, 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 modifier 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.

References

1. http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Classes#Private
2. http://en.wikipedia.org/wiki/Class_%28computer_science%29#Private.2C_protected.2C_and_public
3. http://www.mines.edu/Academic/courses/math_cs/macs262/INFO/Classes_in_Java_and_C++.html#Inheritance
4. Programming Ruby: The Pragmatic Programmers' Guide (Pragmatic Programmers Series) by Dave Thomas, Andy Hunt, Andrew Hunt, Chad Fowler, Chad Fowler [4]