Modules including other modules

Hello,

It appears that including module A inside another module B can cause
problems for classes that have already included A. What seems to
happen is that a class can only see the methods from module B if that
class include module A before module A includes module B.

For example,

module A

def a
puts “a”
end

end

module B

def b
puts “b”
end

end

class C

include B

def c
puts “c”
end

end

module B

include A

def b2
puts “b2”
end
end

C.new.c
C.new.b
C.new.b2
C.new.a

produces

tolsen@neurofunk:~/svn/limeade$ /var/tmp/tst.rb
c
b
b2
/var/tmp/tst.rb:42: undefined method `a’ for #<C:0x2ac204fe7180>
(NoMethodError)

Notice I can define b2() after C has already included B but including
A into B does nothing for C.

Any idea what’s going on here?

Thanks,
Tim

On 2007-05-29, Tim O. [email protected] wrote:

It appears that including module A inside another module B can cause
problems for classes that have already included A. What seems to
happen is that a class can only see the methods from module B if
that class include module A before module A includes module B.

It’s a known problem that is apparently almost impossible to fix. See
eigenclass.org .

Unless there’s been some development that I’ve failed to Google up,
your only option is “Don’t Do That!”. :frowning: Unless Ruby 1.9 handles
things better.

Regards,

Jeremy H.

On May 29, 12:25 pm, Jeremy H. [email protected] wrote:

On 2007-05-29, Tim O. [email protected] wrote:

It appears that including module A inside another module B can cause
problems for classes that have already included A. What seems to
happen is that a class can only see the methods from module B if
that class include module A before module A includes module B.

It’s a known problem that is apparently almost impossible to fix. Seehttp://eigenclass.org/hiki/The+double+inclusion+problem.

Also know as the “Dynamic Inclusion Problem” or just the “Inclusion
Problem”.

Unless there’s been some development that I’ve failed to Google up,
your only option is “Don’t Do That!”. :frowning: Unless Ruby 1.9 handles
things better.

While, it would be great if someone did find a way, from what I
understand its too difficult to fix given how Ruby works, so don’t
hold your breath.

T.

Update: the aforementioned solution was encapsulated into a gem which
makes it feels like it were part of the Ruby language.

Synopsis:
Enumerable.module_eval { retroactively_include MyModule }

At retroactive_module_inclusion | RubyGems.org | your community gem host one may find
the link to the GitHub repository, documentation, bug tracker, etc.

Well, this limitation can be circumvented by runnning the following
after each change in MyModule:

ObjectSpace.each_object(Module) do |m|
if m <= Enumerable
m.module_eval(“include MyModule”)
end
end

In order to understand the drawbacks of this solution, I suggest reading