5

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.

0

2 Answers 2

7

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
Sign up to request clarification or add additional context in comments.

Comments

7

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.

3 Comments

Out of curiousity, what would happen if b was a method that belongs to a class? would a also belong to that class?
@eshalev: yes. (but a would only be defined after b is run for the first time (the def statement needs to be run to define the method))
a) a method is 100% a "function". So is a lambda. b) methods don't need to be explicitly tied associated with a module or class. You are correct about the total weirdness of them being defined at the same level but only after the outer one has been called.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.