CSC/ECE 517 Fall 2007/wiki1b 1 as: Difference between revisions
No edit summary |
|||
Line 14: | Line 14: | ||
== 1. Method Name Conflict == | == 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 | module Foo | ||
def bar | def bar | ||
"hello" | "hello" | ||
end | end | ||
end | end | ||
Line 25: | Line 24: | ||
def bar | def bar | ||
"goodbye" | "goodbye" | ||
end | end | ||
end | end | ||
Line 35: | Line 31: | ||
end | 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 | z = Zap.new | ||
puts z.bar | puts z.bar | ||
The result of this call is: | |||
goodbye | 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 == | == 2. Using Namespaces to Avoid Conflict == | ||
Line 145: | Line 144: | ||
#[http://www.recentrambles.com/pragmatic/view/69 Modules, Mixins, and Inheritance] | #[http://www.recentrambles.com/pragmatic/view/69 Modules, Mixins, and Inheritance] | ||
#[http://www.rubyist.net/~slagell/ruby/modules.html Ruby User's Guide] | #[http://www.rubyist.net/~slagell/ruby/modules.html Ruby User's Guide] | ||
Revision as of 19:41, 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
module Grouchy 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') @name = name end
end person = Person.new('Charlie') Grouchy.say_hello(person.name)
It products:
Charlie says: Don't tell me what to do!
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
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:
- using namespaces
- 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.