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

Jon Leighton j at jonathanleighton.com
Sun Nov 13 15:23:38 PST 2011


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>

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>

FWIW, there has been some discussion of a "prepend module" feature for
Ruby 2, which would address this use case. See
http://redmine.ruby-lang.org/issues/1102.

Jon

-- 
http://jonathanleighton.com/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: This is a digitally signed message part
URL: <http://lists.lrug.org/pipermail/chat-lrug.org/attachments/20111113/6d954556/attachment.sig>


More information about the Chat mailing list