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.