What is the problem with this module function

I have a simple class A declared as follows:

class A

def foo
p “A::foo”
end

def boo
p “A::boo”
end

end

Then I have a simple module ModuleA declared as follows:

module ModuleA
def module_a_foo
p ‘ModuleA::module_a_foo’
end

def foo
p ‘ModuleA::foo’
end
end

I declare an instance of class A as follows:

a1 = A.new
a1.methods.sort
I get all the methods that are declared in class A in my irb console

when I call a1.foo it prints the following as expected
"A::foo’

Now I reopen class A and include moduleA into this class as follows

class A
include ModuleA
end

Now when I type a.methods.sort as expect it displays the methods from
ModuleA also

When I call ‘a1.module_a_foo’ it prints the following as expected.
“ModuleA::module_a_foo”

However now when I call a1.foo I am expecting it to print
“ModuleA::foo” instead I still get “A::foo”.

I am expecting it to print ModuleA::foo because the method foo in
ModuleA would overwrite the method foo when I include ModuleA after
reopening the class A later. Am I missing something here, can anyone
help me understand this.

Kiran K.

On 3/22/07, SunRaySon [email protected] wrote:

I am expecting it to print ModuleA::foo because the method foo in
ModuleA would overwrite the method foo when I include ModuleA after
reopening the class A later. Am I missing something here, can anyone
help me understand this.

Kiran K.

Kiran,

You are mistaken about the method lookup precedence in Ruby. The method
is
first looked up in the class, then mixin modules, then superclasses,
etc.

Therefore, the class definition of “foo” is masking the module
definition of
“foo”, not the other way around.

  • chopper

On Mar 22, 10:47 am, SunRaySon [email protected] wrote:

I am expecting it to print ModuleA::foo because the method foo in
ModuleA would overwrite the method foo when I include ModuleA after
reopening the class A later. Am I missing something here, can anyone
help me understand this.

I suppose the question is “Why were you expecting the module to
overwrite the instance methods defined in the class?”

Modules included in a class insert themselves after the class itself,
but before the ancestor of the class:

module Mod
def foo; “Mod#foo”; end
end

class A
def foo; “A#foo”; end
end

class B < A
include Mod
end

p A.new.foo, B.new.foo
“A#foo”
“Mod#foo”

This diagram might help (although perhaps I could improve it a little
bit to clarify this particular case):

On Mar 22, 11:31 am, SunRaySon [email protected] wrote:

Now I am just curious to know if there is any way I can call the
module function foo from instance a1.

module M
def foo; “M#foo #{self.object_id}”; end
end

class A
include M
def foo; “A#foo #{self.object_id}”; end
def mfoo
M.instance_method( :foo ).bind( self ).call
end
def superfoo
true_ancestors = self.class.ancestors - [self.class]
true_ancestors.each{ |anc|
if m = anc.instance_method( :foo )
return m.bind( self ).call
end
}
nil
end
end

a = A.new
p a.foo, a.mfoo, a.superfoo

Also is there any reason why mixin modules are looked upon first
before looking at superclasses, again I am mistaken here I was opinion
that it would be supreclass and then mixin modules.

Your expectations surprise me. Did you expect that if you had:

class A; end
class B < A; end
class C < B; end
class D < C
include M
end
class E < D; end
e = E.new
e.foo

that Ruby would look for Foo in E, D, C, B, A and then look in M?
Or did you expect E, D, C, M, B, A?

Ruby looks in E, then D, then M, then C, then B, then A. The reason
(or at least a reason that makes sense to me) is:

a) Look in yourself before you look any higher.
b) Modules explicitly included in yourself are more important than
your superclass.

I think these make sense. Do they make sense when you think about them
like that?

Thanks for the clarification.

Now I am just curious to know if there is any way I can call the
module function foo from instance a1.

Also is there any reason why mixin modules are looked upon first
before looking at superclasses, again I am mistaken here I was opinion
that it would be supreclass and then mixin modules.

Kiran K…

On 3/22/07, Phrogz [email protected] wrote:

Ruby looks in E, then D, then M, then C, then B, then A. The reason
(or at least a reason that makes sense to me) is:

a) Look in yourself before you look any higher.
b) Modules explicitly included in yourself are more important than
your superclass.

This is in general true, however, there’s a quirk,

module M
def foo
p ‘M::foo’
end
end

class A
include M
end

class B < A
def foo
p ‘B::foo’
end
end

class C < B
include M
end

Now for the quiz

A.new.foo ==> “M::foo”
B.new.foo ==> “B::foo”
C.new.foo ==> ?

Now you might expect that since C explicitly re-included M that it
should be
“M::foo”, however instead it’s “B::foo”.

I know why this happens based on what the implementation of module
inclusion does, I don’t understand WHY it does it that way. It’s just
the way it is.

For a time, Ruby1.9 allowed re-inclusion of a module by a subclass and
C.new.foo DID return “M::foo”, but for some reason, the current 1.9
(or at least the latest version I’ve gotten from SVN) has gone back to
the old behavior.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Oops! Now I understand how dumb I was, in expecting the superclass
methods being looked upon first.

Kiran.