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

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(12 intermediate revisions by the same user not shown)
Line 4: Line 4:
<i>
<i>


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?
&nbsp;&nbsp;&nbsp;&nbsp; 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?


</i>
</i>
Line 28: Line 28:
           foo
           foo
         end
         end
        def test1
      end
          self.foo
        end
    end


     Output :
     Output :
     irb(main):170:0> Base.new.test
     irb(main):170:0> Base.new.test
     foo
     foo
     irb(main):171:0> Base.new.test1
     irb(main):171:0> Base.new.foo
     NoMethodError: private method `foo' called for #<Base:0x695e9d4>
     NoMethodError: private method `foo' called for #<Base:0x695e9d4>
          from (irb):166:in `test1'
           
          from (irb):171
 
 
      
      


Example -1 shows that private methods can be called only with an implicit receiver. Even calling a private method using self throws NoMethodError.<br>
Example -1 shows that private methods can be called only with an implicit receiver. Calling a private method using an explicit receiver throws NoMethodError. <i>Base.new.foo</i> is the explicit receiver which is trying to call the private method, hence throwing NoMethodError.<br>


Private methods cannot be invoked using an explicit receiver. But we use self to invoke writer methods else the method will be interpreted as an assignment to a local variable.<br>
Private methods cannot be invoked using an explicit receiver. But we use "self" to invoke writer methods else the method will be interpreted as an assignment to a local variable.<br>


<h3>Comparing the private method invocation in C++ and Ruby</h3> <br>
<h3>Comparing the private method invocation in C++ and Ruby</h3> <br>
Line 64: Line 58:
     };
     };


Example -2 shows that a private method can be called by any instance of the same class.
Example -2 shows that a private method can be called by any instance of the same class. <i>otherObject</i> is the instance of the same class <i>Base</i>, which calls the private method foo successfully.


Example -3:
Example -3:


     class Base
     class Base
    private
        private
      def foo; end
        def foo
    public
            puts "foo"
      def spam(otherObject)
        end
        foo             # this is allowed in Ruby (self is implicit)
        public
        self.foo       # Throws a error – NoMethodError private method `foo' called for #<Base:0x66b0dcc>
        def test
        otherObject.foo # Throws a error
            foo
      end
            self.foo
        end
     end
     end
    b = Base.new
    b.test
    Output:
        foo
        NoMethodError: private method `foo' called for #<Base:0x4ef2690>


Example -3 shows, when calling a private method a receiver cannot be specified in Ruby.<br>
Example -3 shows that when calling a private method a receiver cannot be specified in Ruby. Even calling the private method <i>foo</i> through <i>self</i> throws NoMethodError.<br>


So it can be concluded that in C++, “private” defines “private to the class”, while in Ruby it states “private to this instance”.
So it can be concluded that in C++, “private” defines “private to the class”, while in Ruby it means “private to this instance”.


<h3>Bypassing private method invocation in Ruby</h3>
<h3>Bypassing private method invocation in Ruby</h3>


Example -4:
Example -4:
Line 97: Line 98:
     t.send( "print_hello" )
     t.send( "print_hello" )


     Output: Hello everyone!
     Output:  
      Hello everyone!


Example -4 shows that it is possible to access private methods in Ruby through “send” function. Declaring as private is only a guideline in Ruby than a strict rule. There are workarounds to access those private methods. The advantage of such workarounds allows testing of private methods but it is a bad practice since private methods are internals of a class.
Example -4 shows that it is possible to access private methods in Ruby through “send” function. In Ruby, declaring as private is only a guideline and not a strict rule. There are workarounds to access those private methods. The advantage of such workarounds allows testing of private methods but it is a bad practice since private methods are internals of a class.
<br>
<br>
Since private methods have a loophole of security, alternative good practice would be to use accessor functions. In accessor functions, we implement the getter and setter methods for the private attributes, thereby providing the required security.<br>
Since private methods have a loophole in security, an alternative good practice would be to use accessor functions. In accessor functions, we implement the getter and setter methods for the private attributes, thereby providing the required security.<br>
The advantages of using accessor function are – <i>Flexibility </i> and <i> Maintainability</i>
 
There are three accessor functions in Ruby – <br>
<i>attr_reader </i>– creates a getter method.<br>
<i>attr_writer </i>– creates a setter method.<br>
<i>attr_accessor </i>– creates getter and setter methods.<br>
 
Example -5:
 
    class Vehicle
      attr_reader :model
      attr_writer :color
      attr_accessor :price
          def initialize(model,color,price)
              @model = model
              @color = color
              @price = price
          end
    end
    v = Vehicle.new("Camry","black",20000)
    puts v.model
    puts v.color  #throws NoMethodError
    puts v.price
    v.price = 30000
    puts v.price
 
    Output:
        Camry
        NoMethodError: undefined method `color' for #<Vehicle:0x66604d0 @model="Camry", @price=40000, @color="black">
        20000
        30000
 
Example -5 shows the implementation of the accessor functions. The <i>model</i> attribute has only a getter method, hence we cannot set a value to it. The <i>color</i> attribute has only a setter method, hence we cannot read value from it. But <i>price</i> has both getter and setter methods, hence we can read and write value to it.<br>
 
The advantages of using accessor functions are – <i>Flexibility </i> and <i> Maintainability</i>


<li> Since the implementation is confined to the accessor functions, any future changes needs to be made at a single point.</li>
<li> Since the implementation is confined to the accessor functions, any future changes needs to be made at a single point.</li>
Line 109: Line 144:


<br>
<br>
In general, it is a good programming practice to use accessor functions instead of invoking private methods in Ruby.
In general, it is a good programming practice to use accessor functions instead of invoking private methods in Ruby.<br>
 
 
<h3>References</h3><br>
1. Programming Ruby: The Pragmatic Programmers' Guide<br>
2. http://www.rubycentral.com/pickaxe/win32.html<br>
3. http://lylejohnson.name/blog/?p=5<br>
4. http://www.ruby-forum.com/topic/120257#new<br>

Latest revision as of 01:35, 20 September 2007

Private Method Invocation in Ruby


     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?

Ruby’s Access Control Mechanisms

Ruby has three levels of access controls – Public, Protected and Private.

Public methods – can be accessed by anyone. In Ruby, public is default access control, except for initialize method which is private by default.
Protected methods – can be accessed only by the defining class and its subclasses. Access is kept within the family.
Private methods – can be accessed only by the objects of the defining class. The explicit receiver is always self (the current object), which means that it is impossible to invoke another object’s private methods and variables directly even if the object has the same class type as the caller.


Example -1:

   class Base
     private 
       def foo
         puts "foo"
       end
     public
       def test
         foo
       end
     end
   Output :
   irb(main):170:0> Base.new.test
   foo
   irb(main):171:0> Base.new.foo
   NoMethodError: private method `foo' called for #<Base:0x695e9d4>


Example -1 shows that private methods can be called only with an implicit receiver. Calling a private method using an explicit receiver throws NoMethodError. Base.new.foo is the explicit receiver which is trying to call the private method, hence throwing NoMethodError.

Private methods cannot be invoked using an explicit receiver. But we use "self" to invoke writer methods else the method will be interpreted as an assignment to a local variable.

Comparing the private method invocation in C++ and Ruby


The private methods in C++ can be invoked by another object of the same class whereas Ruby does not allow explicit receiver for private methods.

Example -2:

   class Base {
   private:
       void foo();
   public:
       void spam(Base *otherObject) {
           foo();              // this is allowed
           otherObject->foo(); // and so is this
       }
   };

Example -2 shows that a private method can be called by any instance of the same class. otherObject is the instance of the same class Base, which calls the private method foo successfully.

Example -3:

   class Base
       private
        def foo
            puts "foo"
        end
       public
        def test
            foo
            self.foo
        end
   end
   b = Base.new
   b.test
   Output:
       foo
       NoMethodError: private method `foo' called for #<Base:0x4ef2690>


Example -3 shows that when calling a private method a receiver cannot be specified in Ruby. Even calling the private method foo through self throws NoMethodError.

So it can be concluded that in C++, “private” defines “private to the class”, while in Ruby it means “private to this instance”.

Bypassing private method invocation in Ruby

Example -4:

   class Test
     private
       def print_hello
         puts "Hello everyone!"
       end
   end
   t = Test.new
   t.send( "print_hello" )
   Output: 
      Hello everyone!

Example -4 shows that it is possible to access private methods in Ruby through “send” function. In Ruby, declaring as private is only a guideline and not a strict rule. There are workarounds to access those private methods. The advantage of such workarounds allows testing of private methods but it is a bad practice since private methods are internals of a class.
Since private methods have a loophole in security, an alternative good practice would be to use accessor functions. In accessor functions, we implement the getter and setter methods for the private attributes, thereby providing the required security.

There are three accessor functions in Ruby –
attr_reader – creates a getter method.
attr_writer – creates a setter method.
attr_accessor – creates getter and setter methods.

Example -5:

   class Vehicle
     attr_reader :model
     attr_writer :color
     attr_accessor :price
         def initialize(model,color,price)
             @model = model
             @color = color
             @price = price
         end
   end
   v = Vehicle.new("Camry","black",20000)
   puts v.model
   puts v.color  #throws NoMethodError
   puts v.price
   v.price = 30000
   puts v.price
   Output:
       Camry
       NoMethodError: undefined method `color' for #<Vehicle:0x66604d0 @model="Camry", @price=40000, @color="black">
       20000
       30000

Example -5 shows the implementation of the accessor functions. The model attribute has only a getter method, hence we cannot set a value to it. The color attribute has only a setter method, hence we cannot read value from it. But price has both getter and setter methods, hence we can read and write value to it.

The advantages of using accessor functions are – Flexibility and Maintainability

  • Since the implementation is confined to the accessor functions, any future changes needs to be made at a single point.
  • Any type checking that needs to be done can be included within the accessor function. This prevents the object from getting into an inconsistent state.

  • In general, it is a good programming practice to use accessor functions instead of invoking private methods in Ruby.

    References


    1. Programming Ruby: The Pragmatic Programmers' Guide
    2. http://www.rubycentral.com/pickaxe/win32.html
    3. http://lylejohnson.name/blog/?p=5
    4. http://www.ruby-forum.com/topic/120257#new