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", <font color='red'>"One"</font>, "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",<font color='red'>"Two"</font>, "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 <font color='red'>-:35: One is not a class (TypeError)</font>

Posted in  | Tags , , ,  | 1 comment

Comments

  1. AlexW said 156 days later:

    Great article! I've also run into this problem but had no idea what was causing it!

    Thanks!

(leave url/email »)

   Preview comment