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.