Inspired by this article, I was playing around with the Ruby method calling hierarchy and noticed something strange.
Given:
class B
def foo
"- Instance method defined by B"
end
def method_missing(method)
puts "- method_missing (#{method}) on b. Redirecting to b.foo\n"
foo
end
end
b = B.new
def b.foo
"- Method defined directly on an instance of B\n" + super
end
def b.method_missing(method)
"- method_missing (#{method}) on b. Calling super\n" + super
end
puts "Calling 'bar' on b of type #{b.class}:"
puts b.bar
Running it gives:
Calling 'bar' on b of type B:
- method_missing (bar) on b. Redeirecting to b.foo
- method_missing (bar) on b. Calling super
- Method defined directly on an instance of B
- instance method defined by B
My question is:
Since I am calling b.bar (on the object), how come the class's instance method is called before the objet's instance method is called?
I would have expected b.method_missing(method)
to be called first, then the class's instance method_missing(method)
(since I am calling super? but super is class hierarchy...) which the does the redirect from bar
to foo
.
Also, how come, after being redirected to foo
, the instance's missing_method is called? We were just told that we're being redirected...
I think I don't understand the concept of how Ruby allows to define an instance method on an instance of a class (new to me), as opposed to defining it as an instance method of a the class (classic languages).
I hope this question makes sense, maybe my head is still spinning from last night...
The problem is that your output does not reflect the actual order of execution. Let's take a look at the output:
method_missing (bar) on b. Redeirecting to b.foo
method_missing (bar) on b. Calling super
At first glance, this gives the impression that B#method_missing
is called before the singleton method b.method_missing
which raises the two questions you describe. Actually though, b.method_missing
is correctly called first. This gets clear if you look at how the statement puts b.bar
is evaluated:
b
has no method bar
, so b.method_missing
is called with the string 'bar'
as an argument.b.method_missing
in turn calls the method B#method_missing
through use of the super
keyword.B#method_missing
uses puts
to output the first line seen aboveb.foo
is called puts
is performed, which outputs the string in b.method_missing
along with the return value of b.foo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With