CSC/ECE 517 Fall 2007/wiki1b 1 as: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
Line 42: Line 42:


== 2. Using Namespaces to Avoid Conflict ==
== 2. Using Namespaces to Avoid Conflict ==
Using namespaces within the modules will make the method names unique and help disambiguate any conflicts. The namespace is created simply by prefixing the method name with the module name and a period (i.e., Module.method).


  module Grouchy
Let's modify the previous example to include namespaces.
  def Grouchy.say_hello(string='somebody')
    puts "#{string} says: Don't tell me what to do!"
  end
  end
 
Grouchy.say_hello is the class method of the module Grouchy
We have a class Person which includes the module Grouchy
 
class Person
 
  require "grouchy"
 
  attr_accessor :name


   def initialize(name='somebody')
   module Foo
    @name = name
    def Foo.bar #the method name is qualified
        "hello"
    end
   end
   end
  module Test
    def Test.bar #the method name is qualified
        "goodbye"
    end
  end 
  class Zap
  include Foo
  include Test


end
Zap class defines a method called bar, and makes a call to both bar methods in Foo and Test. If the programmer knew for sure that any call to the bar method should invoke only one of the modules, this could be handled here by only calling the module of choice.
person = Person.new('Charlie')
  def bar
Grouchy.say_hello(person.name)
      puts Foo.bar
      puts Test.bar
  end


It products:
  z = Zap.new
  puts z.bar


Charlie says: Don't tell me what to do!
This will produce:
  Hello
  Goodbye


When facing the name conflicts problem, we can use namespace to tell the different of two methods.


module Debug
  def Debug.who_am_i
    "Debug"
  end
end


module Burp
  def Burp.who_am_i
    "Burp"
  end
end
class EightTrack
  include Debug
  include Burp
  def who_am_i
    puts Burp.who_am_i
    puts Debug.who_am_i   
  end
end
et = EightTrack.new
et.who_am_i
It products:
Burp
Debug
Another way is using the alias method, we still have two modules have the same name method who_am_i.
module Debug
  def who_am_i
    "Debug"
  end
end
module Burp
  def who_am_i
    "Burp"
  end
end


class RubyTest   
class RubyTest   

Revision as of 20:13, 10 October 2007

Background

Ruby does not implement true multiple inheritance, but provides Modules as a way to reuse chunks of codes in many classes.

Modules, unlike like classes in OO languages such as Java, cannot be instantiated or sub-classed. Modules are included in class definitions by using the ‘include’ method which will mix that module’s methods into the calling class. The module’s methods will then become instance methods.

A class can include several modules within the class definition. However, a problem exists when a class includes multiple modules that contain a method of the same name. Since the class will have access to both of these methods, unexpected behavior may occur when the names of the methods conflict.

Let’s look at a few examples!

Examples

1. Method Name Conflict

In the following example, we have the class Zap. This class includes the module Foo and the module Test. Both modules contain a method named bar.

  module Foo
     def bar
        "hello"
     end
  end
  module Test
     def bar
        "goodbye"
     end
  end   
  class Zap
   include Foo
   include Test
  end

If a call is made to Zap's bar method, the caller is unsure whether the result will be "hello" or "goodbye".

  z = Zap.new
  puts z.bar

The result of this call is:

  goodbye

This is because Ruby will first search the last module included, and continue in a descending order. The method that is invoked may not be the method that the caller expected to run. Therefore, precaution to be taken within the class to eliminate ambiguity.

2. Using Namespaces to Avoid Conflict

Using namespaces within the modules will make the method names unique and help disambiguate any conflicts. The namespace is created simply by prefixing the method name with the module name and a period (i.e., Module.method).

Let's modify the previous example to include namespaces.

 module Foo
    def Foo.bar #the method name is qualified
       "hello"
    end
 end
 module Test
    def Test.bar #the method name is qualified
       "goodbye"
    end
 end   
 class Zap
  include Foo
  include Test

Zap class defines a method called bar, and makes a call to both bar methods in Foo and Test. If the programmer knew for sure that any call to the bar method should invoke only one of the modules, this could be handled here by only calling the module of choice.

  def bar 
     puts Foo.bar
     puts Test.bar
  end
  z = Zap.new
  puts z.bar

This will produce:

  Hello
  Goodbye



class RubyTest

 include Burp  
 alias :Burp_who_am_i :who_am_i   
 include Debug
 alias :Debug_who_am_i :who_am_i   

end

rt = RubyTest.new puts rt.Debug_who_am_i puts rt.Burp_who_am_i

3. Using Aliases to Avoid Conflict

Conclusion

As illustrated in the examples, there are at least two ways to ensure that your class runs as expected even when using modules with method name conflicts.

The two approaches are:

  1. using namespaces
  2. using an alias

In our opinion, using namespaces is the better approach. Inheriting from the module and using the qualified names to avoid conflicts is a more efficient OO design. It is also easier to read and maintain because in viewing the call, a reader will immediately gather the expected behavior of the call, as opposed to finding the alias definition and trying to make the connection.

With the alias approach, the inheritance is limited and the programmer will need to constantly update the list of aliases for methods needed as they arise.

References

  1. Modules, Mixins, and Inheritance
  2. Ruby User's Guide
  3. 'use' package readme