Yesterday I wrote about an interesting behaviour Ruby exhibits when resolving instance variables in global functions. It turns out I was wrong. A bit.
I said that anything defined in the global scope is actually defined on the object called "main," which is an instance of Object
. However, that's actually a little bit incorrect, and as a result, while my analysis of scripts 2 and 3 from that post are correct, the premise that lead me to create them in the first place was flawed.
The real truth is this: any function defined in the global scope is actually defined as a method in the Object
class. This means that every object in Ruby inherits the method; which means that whenever it's called from within another method, that object (the one who owns the other method, not "main") becomes the receiver; and because it's defined on the obect (in its inheritance tree) it has access to that object's instance variables. So, in the example I posted yesterday, it rightfully returns the Bar
object's @foo
, which equals 42
.
Because I assume my words are convoluted, here it is represented in code form:
Script 1 | Script 4 |
---|---|
def foo @foo end class Bar def initialize @foo = 42 end def bar foo end end p foo p Bar.new.bar |
class Object def foo @foo end end class Bar def initialize @foo = 42 end def bar self.foo end end p foo p Bar.new.bar |
And, of course, the requisite output:
Script 1 | Script 4 |
---|---|
$ ruby script1.rb nil 42 |
$ ruby script4.rb nil 42 |
The "main" object's foo returns nil
, but the Bar object's returns 42
.
And now you know.