[LRUG] Can't hide instance method if defined in native extension?

Peter Vrabel kybu at kybu.org
Sun Nov 13 16:00:34 PST 2011


On Sun, 13 Nov 2011 23:23:38 -0000, Jon Leighton <j at jonathanleighton.com>  
wrote:

> On Sun, 2011-11-13 at 22:35 +0000, Peter Vrabel wrote:
>> Well, I can do that if that class is written in pure Ruby, for example
>> 'Set'. Consider this:
>>
>> module MySet
>>    def size
>>      puts "mine!"
>>    end
>> end
>>
>> class Set
>>    include MySet
>> end
>>
>> set = Set.new [1, 2, 3]
>> p set.method(:size)
>>
>> It gives following output:
>> #<Method: Set(MySet)#size>
>
> This example code won't run as-is. Assuming you did "require 'set'"
> previously, it gives:
>
> #<Method: Set#size>

Thanks for pointing this out. I did have that snippet along with mysql  
snippet
in one file and when you require mysql, it does for some strange reason  
work as
I wrote. I tried my set snippet alone and you are right.

> If Set was not already defined (i.e. you did not require 'set'), and you
> instantiate the instance without the argument (e.g. "Set.new" not
> "Set.new [1, 2, 3]", otherwise you'll get an error), then it will indeed
> give #<Method: Set(MySet)#size>.
>
> But this is because there is no Set#size method, so Ruby looks further
> up the ancester chain, and gets to MySet#size.
>
> Method dispatch in ruby works (broadly speaking) by looking for the
> first method with the desired name in the ancestor chain. When you
> include a module, that module is inserted in the ancestor chain. But if
> the method is actually defined on the class, then that method is used
> instead, because the class is closer to the start of the ancestor chain.
>
> For example:
>
> [1] pry(main)> module A
> [1] pry(main)*   def foo
> [1] pry(main)*   end
> [1] pry(main)* end
> => nil
> [2] pry(main)> class B
> [2] pry(main)*   include A
> [2] pry(main)* end
> => B
> [3] pry(main)> B.ancestors
> => [B, A, Object, PP::ObjectMixin, Kernel, BasicObject]
> [4] pry(main)> B.new.method(:foo)
> => #<Method: B(A)#foo>
> [5] pry(main)> class B
> [5] pry(main)*   def foo
> [5] pry(main)*   end
> [5] pry(main)* end
> => nil
> [6] pry(main)> B.new.method(:foo)
> => #<Method: B#foo>

I recently read an article about Ruby method lookup and I got it wrong. I  
do understand it now, thanks for your help.
Ancestors method is quite handy in situations like this.

Cheers,
   kybu



More information about the Chat mailing list