Global Functions in Ruby, Updated

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 1Script 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 1Script 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.


Matthew Kerwin

Published
Modified
License
CC BY-SA 4.0
Tags
development, gotcha, ruby, software
Yesterday I wrote about an interesting behaviour Ruby exhibits when resolving instance variables in global functions. It turns out I was wrong. A bit.

Comments powered by Disqus