[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

What is the problem with this module function.

SunRaySon

3/22/2007 4:48:00 PM

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 Kumar

6 Answers

Gavin Kistner

3/22/2007 5:03:00 PM

0

On Mar 22, 10:47 am, SunRaySon <sunray...@gmail.com> 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):

http://phrogz.net/RubyLibs/RubyMethodLook...

SunRaySon

3/22/2007 5:32:00 PM

0

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


On 3/22/07, Ron Hopper <rchopper@gmail.com> wrote:
> On 3/22/07, SunRaySon <sunrayson@gmail.com> 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 Kumar
> >
> >
>
> 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
>

Gavin Kistner

3/22/2007 7:48:00 PM

0

On Mar 22, 11:31 am, SunRaySon <sunray...@gmail.com> 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?

Rick DeNatale

3/23/2007 6:26:00 PM

0

On 3/22/07, Phrogz <gavin@refinery.com> 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.denh...

SunRaySon

3/24/2007 3:53:00 AM

0

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

Kiran.


On 3/23/07, Phrogz <gavin@refinery.com> wrote:
> On Mar 22, 11:31 am, SunRaySon <sunray...@gmail.com> 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?
>
>
>

u2fan

2/3/2009 10:33:00 PM

0

On 3 Feb, 21:24, u2fan <newu2...@googlemail.com> wrote:
> On 3 Feb, 17:20, "Ike24" <yeickleberrybo...@msn.com> wrote:
>
>
>
> > "u2fan" <newu2...@googlemail.com> wrote in message
>
> >news:09936019-b1d6-413b-a9e4-8c60aea43d27@q30g2000prq.googlegroups.com...
>
> > > Mohamed was delighted it all seemed in place, Ahmadjihad rang him up
> > > "right go for it, blow that damn Israel up now, allah is great
>
> > Except prophecy doesn't say anything about the Muslims "blowing up" Israel,
> > moron.
>
> > Israel and Islam are led into false peace, NOT WAR, by the false prophet.
>
> > Totally clueless, you are.
>
>> [snip]
>
> > Ike
>
Clueless ? I don't think so but I'll leave you clueless, obviously you
can't push such a story before the event but you can tell an encypted
message before it happens
120,172,171,150,154,163,47,150,173,173,150,152,162,172,47,120,171,150,165,160,150,165,47,165,174,152,163,154,150,171,47,172,160,173,154,172