Method lookup is an interesting topic in Ruby. For example, exactly what happens that produces this output from this code?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
The algorithm for method lookups can be summarized in one sentence: “one step to the right, then up”. This is referring a specific visualization of objects and classes relationships, where we place object’s class to the right from the object, and place ancestor of a class above it.
It’s important to understand that instances in ruby do not hold methods, only classes do. At the same time we’re able to enhance specific instances with additional methods, that other instances of the same class will not have. Look:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Here bar2
instance does not have a hello
method, while bar1
does have it. This means
that hello
method can’t be in bar1
instance itself (remember, instances don’t contain
methods), but it also can’t be in Bar
class, because then bar2
would also have it. So,
where is that method located?
Well, there is a special hidden class for every object instance in ruby. This dynamic class is where all those per-instance methods go. You won’t be able to see it in the ancestors chain, ruby hides it from you. But it’s there (well, technically speaking, it appears there when you define your first per-instance method). So, in this case the lookup goes like this:
But what happens if Bar
also defines a hello
method? Which gets found and executed first?
Can you tell by looking on the pictures above?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
That’s right it will print “bar”, then “foo”. Why? Because Foo#hello
will be injected
before Bar#hello
in the ancestors chain. It will go into that dynamic unique class
(which is called eigenclass, by the way). Here’s the lookup flow:
Method from Foo
is found first and it calls super, which is the version in Bar
class.
This version also tries to call super
(there isn’t one), then prints “bar” and returns
control to Foo#hello
which prints “foo”.
Now you see, it’s a simple algorithm. But it can be really puzzling if you don’t know about eigenclasses.