# Calling non-existing methods works! (little magic?)

**URL:** <https://www.ruby-forum.com/t/calling-non-existing-methods-works-little-magic/64860>\
**Category:** Ruby\
**Created:** [August 15, 2006, 2:19pm UTC](https://www.ruby-forum.com/t/calling-non-existing-methods-works-little-magic/64860 "2006-08-15T14:19:54Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Martin\_SSWeber](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@Martin\_SSWeber](https://www.ruby-forum.com/u/Martin_SSWeber)\
**Post date:** [August 15, 2006, 2:19pm UTC](https://www.ruby-forum.com/t/calling-non-existing-methods-works-little-magic/64860/1 "2006-08-15T14:19:54Z")

</div>

Hoi Rubyists.

I am kind of … confused. Up till now I had the illusion you could only  
call methods on an object which you could also find via methods or via  
the included modules. Fine… Why does this output what it does then?  
Where is this method defined? Some kind of method lookup cache? How to  
force flushing it (besides redefining the methods of the receiver?)

Thanks in advance for the help,

-Martin

— snippiesnap: fun\_delegate.rb —  
class A; def a; “a”; end; end  
class B; def b; “b”; end; end

# obvious: return difference of instance methods, ignoring

“method\_missing”  
def inst\_meth\_delta( klass1, klass2 )  
klass1.instance\_methods - klass2.instance\_methods - [  
“method\_missing” ]  
end

# obvious:P

# if delegation is to be established, create an anonymous module, define

# methods on it to delegate to the receiver, extend the sender with this

# module.

# if delegation is to be deleted, remove methods from the anonymous

module.  
def fun\_delegate(snd, rcv)  
return unless (snd && rcv)

```
    deinstalled=false;
    # maybe remove the delegation again?
    (class << snd ; included_modules ; end).each do |mod|
            # get the source object_id (obj which is delegated to)
            dd = mod.instance_variables.include?('@dd') && 

```

mod.instance\_variable\_get(:@dd)  
# deinstall methods if rcv is delegated to a second  
# time - or when rcv is :off.  
if dd && (dd == rcv.object\_id || rcv == :off) then  
puts “Removing delegation from #{snd} to #{rcv}  
(mod: #{mod})”  
mod.instance\_methods.each do |meth|  
mod.send(:remove\_method, meth.intern)  
end  
deinstalled=true;  
mod.instance\_variable\_set(:@dd, nil)  
end  
end

```
    # ... or set it up?
    unless deinstalled
            (mod = Module.new).instance_variable_set(:@dd, 

```

rcv.object\_id)  
puts “delegating from #{snd} to #{rcv} via #{mod}…”  
inst\_meth\_delta(rcv.class, snd.class).each {|meth|  
mod.send(:define\_method, meth.intern) {|\*args|  
rcv.send(meth.intern, \*args) }  
}  
snd.extend(mod)  
end

end

a=A.new; b=B.new

# obvious so far

# nometherr

begin puts a.b rescue puts $! end  
fun\_delegate a,b

# “b”

begin puts a.b rescue puts $! end  
fun\_delegate a,b

# MAGIC!!!

# “b”

begin puts a.b rescue puts $! end

# Fine, where is this “b” coming from?

puts a.methods.find{|m| m==‘b’} ;# -\> nil  
puts a.methods - Kernel.methods ;# -\> “a”  
puts a.singleton\_methods ;# -\> []  
puts “#{(class \<\< a ; included\_modules ; end).collect {|mod|  
mod.instance\_methods unless mod.name == “Kernel”  
}}” ;# -\> [[], nil]  
— snappiesnip: fun\_delegate.rb —

— output —  
$ ruby -vw fun\_delegate.rb  
ruby 1.8.4 (2005-12-24) [i386-netbsdelf]  
undefined method `b’ for #\<A:0x806b618\>  
delegating from #\<A:0x806b618\> to #\<B:0x806b604\> via  
#Module:0x806b4b0…  
b  
Removing delegation from #\<A:0x806b618\> to #\<B:0x806b604\> (mod:  
#Module:0x806b4b0)  
b  
nil  
a

— end —

---

<div class="post-metadata">

**Author:** ![Martin\_SSWeber](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@Martin\_SSWeber](https://www.ruby-forum.com/u/Martin_SSWeber)\
**Post date:** [August 15, 2006, 2:20pm UTC](https://www.ruby-forum.com/t/calling-non-existing-methods-works-little-magic/64860/2 "2006-08-15T14:20:03Z")

</div>

Martin S. Weber schrieb:

> I am kind of … confused. Up till now I had the illusion you could only  
> call methods on an object which you could also find via methods or via  
> the included modules. Fine… Why does this output what it does then?  
> Where is this method defined? Some kind of method lookup cache? How to  
> force flushing it (besides redefining the methods of the receiver?)  
> (…)

Martin, this seems to be a bug. As you guessed, there is a method lookup  
cache, and it isn’t flushed correctly when removing a method. Here’s a  
simpler code to show the bug…

Define a module, include it in a class and call a method of the module:

module M  
def m  
p “M#m”  
end  
end

class C  
include M  
end

C.new.m

# =\> “M#m”

Remove the method from the module:

module M  
remove\_method :m  
end

The method lookup cache of class C isn’t cleared (bug), so you can still  
call the old method:

C.new.m

# =\> “M#m”

Here’s one way to clear the method lookup cache for a given method:  
create an anonymous module and define a method with the same name:

Module.new do  
def m  
end  
end

C.new.m rescue p $!

# =\> #\<NoMethodError: undefined method `m’ for #\<C:0x2b83d10\>\>

I will forward this to the ruby-core mailing list.

Thanks for the bug report,  
Pit

---

<div class="post-metadata">

**Author:** ![Martin\_SSWeber](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@Martin\_SSWeber](https://www.ruby-forum.com/u/Martin_SSWeber)\
**Post date:** [August 15, 2006, 2:20pm UTC](https://www.ruby-forum.com/t/calling-non-existing-methods-works-little-magic/64860/3 "2006-08-15T14:20:08Z")

</div>

On Tue, Aug 15, 2006 at 02:13:56AM +0900, Pit C. wrote:

> Martin, this seems to be a bug. As you guessed, there is a method lookup  
> cache, and it isn’t flushed correctly when removing a method. Here’s a  
> simpler code to show the bug…  
> […]  
> The method lookup cache of class C isn’t cleared (bug), so you can still  
> call the old method:
> 
> C.new.m
> 
> # =\> “M#m”

[…]

> I will forward this to the ruby-core mailing list.

This was fixed one month ago in both HEAD and ruby\_1\_8:

```
    * eval.c (rb_clear_cache_for_undef): clear entries for included
      module. fixed: [ruby-core:08180]
```

---

<div class="post-metadata">

**Author:** ![Martin\_SSWeber](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/9dc877/32.png) [@Martin\_SSWeber](https://www.ruby-forum.com/u/Martin_SSWeber)\
**Post date:** [August 15, 2006, 2:20pm UTC](https://www.ruby-forum.com/t/calling-non-existing-methods-works-little-magic/64860/4 "2006-08-15T14:20:13Z")

</div>

Mauricio F. schrieb:

> This was fixed one month ago in both HEAD and ruby\_1\_8:
> 
> ```
> * eval.c (rb_clear_cache_for_undef): clear entries for included
> module. fixed: [ruby-core:08180]
> 
> ```

Thanks for the info, Mauricio.

Regards,  
Pit
