I Like Programming

Ruby Doesn’t Have Inner Functions

Ruby syntax allows you to write something that looks a lot like an inner function in other languages. However, it really isn’t. Lets explore this odd behavior.

class Foo
  def bar
    x = "scoped variable"
    def baz
      puts x
    end
  end
end

This looks like a pretty standard test of closures. One might expect the bar method to define a function baz with access to bar’s scope, namely the variable x. Lets see what really happens.

puts Foo.instance_methods.include?("bar") # true
puts Foo.instance_methods.include?("baz") # false

Still consistent with our expectations, we see we have created an instance method bar, but not baz. Lets test out bar on an instance.

instance = Foo.new
instance.bar
puts Foo.instance_methods.include?("baz") # true

Oho, where did this baz method come from that wasn’t there before? Running bar created it! In fact, calling `bar’ in our instance even changed the global class definition to include it! Lets try it out!

instance.baz # NameError: undefined local variable or method ‘x’ for #<Foo:0x1cee4>

So much for closures. It seems baz doesn’t have access to bar’s scope. It’s just a plain old instance method that we’ve defined.

Well, it doesn’t behave much like other languages, but this behavior could still be useful. You could use it to evaluate method definitions conditionally, or just wait and create some of your methods after others have run. It’s not all that useful, but it’s still good to know so you don’t accidentally use this syntax wrong.