If a function loses access to the data it needed from its enclosing scope, that would kind of limit the usability of first class functions and the ability to define and use them anywhere.
In order to fully realize their usefulness, behavior has to be implemented so that the lexically scoped data outlive its enclosing scope.
This concept is known as closure. The lexically scoped data enclosed by the nested function is moved to a different region of memory that persists after the stack has been returned, an upvalue.
local function getFunction()
local counter = 0
local function innerFunction()
counter = counter + 1
print(counter)
end
return innerFunction
end
local foo = getFunction()
foo() --Output: 1
foo() --Output: 2
foo() --Output: 3
print(counter) --Output: nil
This is done automatically by Lua. And now each time that function is called, it references the same upvalue.
Because closures create their own upvalue, each time the enclosing function is called, a new upvalue is created. This makes it possible to define several of the same function that references its own data.
local function getFunction()
local counter = 0
local function innerFunction()
counter = counter + 1
print(counter)
end
return innerFunction
end
local foo = getFunction()
local bar = getFunction()
foo() --Output: 1
foo() --Output: 2
bar() --Output: 1
foo() --Output: 3
foo() --Output: 4
bar() --Output: 2