Ruby Namespace Conflicts
Posted by Mike Blake Sat, 15 Jul 2006 10:30:00 GMT
Declare new Classes Inside Modules to Avoid Conflicts
In the ruby language you cannot have a Module with the same name as a Class. The reason is that in any instance of the ruby interpreter, all root level accessible Objects are stored in a Hash of constants as either Modules or Classes. This can get cluttered pretty quickly in a large application. Try throwing the line 'p Module.constants' in the middle of a medium sized Rails application.
However, if a class is part of a Module, which acts as a namespace in ruby, it’s name never makes it to Module.constants. So it can have the same name as an existing Module.
To see a demonstration of this, I executed the following ruby code.
module One
end
class Two
def self.to_s
"2"
end
end
p Two
class One::Two
def self.to_s
"1::2"
end
end
p One::Two
class One::Three
def self.to_s
"1::3"
end
end
p One::Three
p Module.constants
class One::One
def self.to_s
"1::1"
end
end
p One::One
class One
def self.to_s
"1"
end
end
p One
Here’s what happened. (output below). A Module named One was created and so was a class named Two. And the interpreter saw that it was good. Then, in the One module, classes One, Two, and Three were created. And the interpreter saw that it was good.
Then I took a peek at Module.constants. The One Module, and the Two Class were saved as constants. But the Three Class was not stored as a constant because it is not at the root level. Since Classes created within Modules are not stored as constants,I was allowed to create a One Class inside the One Module without a getting a TypeError.
But all is not well in paradise. When the program tried to create a class named One it got the error
-:35: One is not a class (TypeError)
That’s because it’s already stored in constants as a Module.
As Ruby grows in popularity, this could become a problem. Especially in the Rails framework where all Model objects are at the root level. Considering this, it’s a good habit to use modules as namespaces when creating new classes in things like plugins and gems to avoid a TypeError.
Output:
1::2
1::3
2
["TrueClass", "FloatDomainError", "Fixnum", "TOPLEVEL_BINDING", "SignalException", "String", "SystemCallError", "UnboundMethod", "Buffering", "Rational", "ThreadGroup", "CROSS_COMPILING", "ScriptError", "MatchData", "Thread", "IndexError", "STDOUT", "One", "SecurityError", "Integer", "SingleForwardable", "Config", "RELEASE_DATE", "Exception", "NoMethodError", "Proc", "GC", "TypeError", "Binding", "Signal", "FALSE", "RUBY_PLATFORM", "Forwardable", "Bignum", "SystemExit", "Date", "NotImplementedError", "EOFError", "FileTest", "TRUE", "Numeric", "Interrupt", "ARGF", "Array", "SyntaxError", "MatchingData", "RUBY_VERSION", "ParseDate", "Time", "RangeError", "ENV", "NIL", "Enumerable", "Module", "PLATFORM", "STDERR","Two", "NoMemoryError", "Float", "Regexp", "DateTime", "Data", "ZeroDivisionError", "ARGV", "Dir", "Process", "Range", "ThreadError", "ArgumentError", "Object", "IO", "Comparable", "LocalJumpError", "Math", "Marshal", "RuntimeError", "STDIN", "Method", "VERSION", "RegexpError", "Hash", "Precision", "Kernel", "Continuation", "File", "SystemStackError", "OpenSSL", "FalseClass", "Errno", "NilClass", "StandardError", "LoadError", "ObjectSpace", "RUBY_RELEASE_DATE", "Gem", "IOError", "Symbol", "Struct", "NameError", "Class"]
1::1
-:35: One is not a class (TypeError)

