lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


A closure is a function, plus its environment. This includes its upvalues and its global environment, which in Lua 5.2 is an upvalue called _ENV.

An upvalue is a local that has been declared in a parent scope and not covered over by a local declaration:

local o = function()
local x = 1
return function ()
print (x)
x = x + 1
end
end

local f = o()

f()
--> 1
f()
--> 2
x = 5 -- x is an global here. _ENV.x = 5
f()
--> 3
o = nil --> Lua will collect the function o, but retains the needed up value x
f()
--> 4


On Wed, May 31, 2017 at 18:45 Sean Conner <sean@conman.org> wrote:
It was thus said that the Great J Doe once stated:
>
> The fact that the local reference is made in the same "space" as main()
> would cause me to think that it is in the global scope, because it's free
> of any enclosing function.  However, when I examine the variable in the
> debugger of the Lua plugin in Eclipse Neon (Lua Dev Tools 1.4.1 using Lua
> 5.2 - I realize that I am not using the most up to date version of Lua,
> but the product I am using Lua with - ModSecurity 2.9.1 - uses Lua 5.2),
> the debugger correctly places sin at a scope other than the global scope.
>
> Is it just because I am used to C/C++ rules that I am confused ?  I can
> see that the addition of "local" means "not in the global memory area",
> but what is the scope of the reference to math.sin() actually called in
> this instance ?  What "chunk" does it belong to ?

  A quick way of thinking of it (if you are a C programmer) is "local" is
similar in nature to C's "static"---it's only visible to the file [1].
Behind the scenes, what's happening is

        ************************************************************
        *
        * return function(...)
        *       +------------------------------------
        *       | local sin = math.sin
        *       |
        *       | local function foo(x)
        *       |       for i = 1, 1000000 do
        *       |               x = x + sin(i)
        *       |       end
        *       |       return x
        *       | end
        *       |
        *       | local function main()
        *       |       foo(10)
        *       | end
        *       |
        *       | main()
        *       +------------------------------------
        * end
        *
        *************************************************************

  The inner square is your file (called a "chunk" [2] in Lua parlance). When
the file is loaded and parsed, what you effectively get is in the outer
square---an anonymous function you need to execute.  If you read the
documentation that comes with Lua, it mentions this when describing load()
and loadfile().

  In fact, in the above code, there are several levels of scope:

        +------------------------------------
        | local sin = math.sin
        |
        | local function foo(x)
        }
        | +----------------------------------
        | |     for i = 1, 1000000 do
        | |
        | | +--------------------------------
        | | |           x = x + sin(i)
        | | +--------------------------------
        | |
        | |     end
        | |     return x
        | +----------------------------------
        | end
        |
        | local function main()
        |
        | +----------------------------------
        | |     foo(10)
        | +----------------------------------
        |
        | end
        |
        | main()
        +------------------------------------

  Each box represents a new scope where you can declare local variables.
Local variables outside a scope are called "upvalues" in Lua (in the loop in
foo(), the variable sin is an upvalue).

  -spc

[1]     Not 100% accurate, but close enough.

[2]     The 100% accurate truth.