Nested Mixin Problem(?)


#1

Hi,

could someone check and comment if this is something that i don’t
understand well or a ruby “somehow” problem? please

Here’s the code:

module A
def a; :a; end
end

module B
include A
def b; :b; end
end

module C
def c; :c; end
end

class D
include B
end

D.new.a #=> :a ## Ok for me
D.new.b #=> :b ## Ok for me

module B
include C
end

D.new.c #=> NoMethodError: undefined method `c’ for #<D:0xb7cb985c> ##
This is not ok for me.

Thanks,
Vasco Andrade e Silva


#2

Dear Vasco,

it seems like you wanted to include something before it is
defined.
The following worked for me:

module A
def a; :a; end
end

module B
include A
def b; :b; end
end

module C
def c; :c; end
end

module B # <------ interchanged these
include C
end

class D # <------ interchanged these
include B
end

D.new.a #=> :a ## Ok for me
D.new.b #=> :b ## Ok for me

p D.new.c #=>:c ## Ok for you?

Best regards,

Axel


#3

On 2 Jul 2007, at 10:51, Vasco Andrade e Silva wrote:

include B
0xb7cb985c> ##
This is not ok for me.

Thanks,
Vasco Andrade e Silva


Posted via http://www.ruby-forum.com/.

I think you’ve found an interesting edge case for modules and mixins.
Redefining a module only seems to work to one ‘level’. So this works:

irb(main):001:0> module FooBar
irb(main):002:1> end
=> nil
irb(main):003:0> class Baz
irb(main):004:1> include FooBar
irb(main):005:1> end
=> Baz
irb(main):006:0> a = Baz.new
=> #Baz:0x330568
irb(main):007:0> module FooBar
irb(main):008:1> def foo; :foo; end
irb(main):009:1> end
=> nil
irb(main):010:0> a.foo
=> :foo

But not here (analogous to your example I think):

irb(main):011:0> module Bar
irb(main):012:1> def bar; :bar; end
irb(main):013:1> end
=> nil
irb(main):014:0> module FooBar
irb(main):015:1> include Bar
irb(main):016:1> end
=> FooBar
irb(main):017:0> a.bar
NoMethodError: undefined method `bar’ for #Baz:0x330568
from (irb):18

We need a guru to explain why…

Alex G.

Bioinformatics Center
Kyoto University


#4
> irb(main):016:1> end > => FooBar > irb(main):017:0> a.bar > NoMethodError: undefined method `bar' for # > from (irb):18 > > We need a guru to explain why... That is definitely not me, but there was a very interesting thread by Tom (aka Trans) very recently and Pit provided a nice metaprogramming tool to address the issue which is called "double inclusion". [ Sorry I am bad at finding references to threads :( ]

As a matter of fact there is an easy way to update the method lookup
chain
just continue as follows in your irb session:

irb(main):019:0> class Baz
irb(main):020:1> include FooBar # Play it again Sam
irb(main):021:1> end
=> Baz
irb(main):022:0> a.bar
=> :bar

It has something to do with the proxies that are created for included
modules, maybe a Guru will explain this in detail.

Cheers
Robert


#5

Hi,

Axel E. wrote:

it seems like you wanted to include something before it is
defined.

No. I wanted to use mixins for more than ‘one level’, as Alex G.
explain it:

I think you’ve found an interesting edge case for modules and mixins.
Redefining a module only seems to work to one ‘level’. So this works:

I didn’t know that this “problem” was called “double inclusion” (thanks
Robert) or “Dynamic Module Include Problem”. After a quick search for
“double inclusion” you get:
http://eigenclass.org/hiki/The+double+inclusion+problem
http://www.ruby-forum.com/topic/112897

If some Guru come along and see this thread maybe he/she could give a
more indepth answer.

Meanwhile…
Thank you guys,
Vasco