Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Ruby Nested Functions

Tags:

closures

ruby

I am learning ruby at the moment. I am trying to understand the way closures work, and how they are different from functions. I am fully aware that closures should be implemented via proc or lambda.

I am trying to get an in depth understanding of ruby. As such I checking all kinds of unorthodox code. I am trying to understand why line 3 works while line 5 is an error.

x=123
def b(x)
    p x
    def a(u)
      p x # why is this an error?!?!?
    end
    a 4
end

b 1
  1. If a can't access b's parameters, why doesn't it access the global x=123?
  2. Why does this work if I explicitly use change lines 1 & 5 to the global "$x"?
  3. Why does this work if I use a lambda explictly?

This is purely a learning exercise, I am doing this to understand what is going on beneath the hood.

like image 623
eshalev Avatar asked Dec 25 '22 13:12

eshalev


2 Answers

It's something called the "scope gate". Basically, when you start a definition of a method/class/module, a new scope is created and all local variables from other scopes can't be accessed. This doesn't apply to instance/global variables, you'll keep access to those.

Since a lambda isn't a method, it doesn't create new scope and reuses existing one instead.

Also,

why line 3 works

x = 123
def b(x)
    p x # this "x" is "x the parameter", not "x the local variable from outer scope"
        # that's why it works. If you tried to access the local var, it wouldn't work.
    def a(u)
      p x # like here, see? Doesn't work.
    end
    a 4
end

b 1
like image 152
Sergio Tulentsev Avatar answered Jan 12 '23 08:01

Sergio Tulentsev


The first thing to understand is that def does not make a "function" (what does that even mean in Ruby?) -- def defines a method on some object or class. Even when it appears to be not inside any object, it still defines a method on the "main" object. So when you do def a, it is not "local" to the method b; it is a method a just like if you defined it at the top level, except that it doesn't get defined until b runs. It can be called as the method a from other places. You have nested method definitions.

Because it was meant to define methods, which most of the time is defined at the top level of a class or module, def was never made to capture outside variables.

like image 34
newacct Avatar answered Jan 12 '23 08:01

newacct