Nested Mixin Problem(?)

  • Thread starter Vasco Andrade e Silva
  • Start date
V

Vasco Andrade e Silva

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
 
C

Chris Shea

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

Vasco,

My understanding of this is that you can imagine include just pasting
in the module code when its evaluated. So any changes to the module B
after the include won't be included in the class D, because the
copy&paste into the class has already happened.

HTH,
Chris
 
C

Chris Shea

Vasco,

My understanding of this is that you can imagine include just pasting
in the module code when its evaluated. So any changes to the module B
after the include won't be included in the class D, because the
copy&paste into the class has already happened.

HTH,
Chris

D'oh! I should have looked before I leaped. From Pickaxe:

"Second, a Ruby include does not simply copy the module's instance
methods into the class. Instead, it makes a reference from the class
to the included module. If multiple classes include that module,
they'll all point to the same thing. If you change the definition of a
method within a module, even while your program is running, all
classes that include that module will exhibit the new
behavior." (http://www.rubycentral.com/book/tut_modules.html#S2)

It looks like it's just nested includes after the fact that's the
issue.

Sorry,
Chris
 
K

Ken Bloom

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>

D.included_modules #=> [B, A, Kernel]

If the behavior you expect to occur were occuring, there's no reason why
A would need to be listed in this list, since B would take care of
everything.

Apparently, method resolution doesn't recurse from B to A, rather `include
B' adds B and all of B's included modules directly into D's list of
included modules. Since C was added to B after this had happened, C
couldn't be added to D's list of included modules.

--Ken
 
A

Axel Etzold

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
 
A

Alex Gutteridge

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

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 Gutteridge

Bioinformatics Center
Kyoto University
 
R

Robert Dober

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...
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
 
V

Vasco Andrade e Silva

Hi,

Axel said:
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 Gutteridge
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,058
Latest member
QQXCharlot

Latest Threads

Top