Consider this Lua 5.1 code:
function foo ()
function makeAdder (withWhat)
return function (a)
return a + withWhat
end
end -- makeAdder
f1 = makeAdder (6)
f2 = makeAdder (7)
end -- for
foo ()
print (f1 (2)) --> 8
print (f2 (2)) --> 9
The functions f1 and f2 have 6 and 7 as upvalues to the closures, and thus output 8 and 9 in response to being called. This is what I expect.
Now consider:
function foo ()
local withWhat
function makeAdder ()
return function (a)
return a + withWhat
end
end -- makeAdder
withWhat = 6
f1 = makeAdder ()
withWhat = 7
f2 = makeAdder ()
end -- for
foo ()
print (f1 (2)) --> 9
print (f2 (2)) --> 9
The functions f1 and f2 have 6 and 7 as upvalues to the closures at the time they are created, however they output 9 and 9, which is not what I expect.
I thought f1 and f2 would be closed with their upvalues at the point of their creation, but obviously not. How does 7 become an upvalue for f1, even though it "should" have been 6?
Lua version 5.1.5.
Upvalues of a inner function in lua are copied by address from the enclosing function, resulting in both
f1andf2'swithWhatupvalues in your second code pointing to the same address.There are actually two ways to copy:
If an upvalue of the inner function refers to an upvalue of the enclosing function, lua simply copies the pointer.
This is the case with your second piece of code. As for both
makeAdderandfunction(a),withWhatis their upvalue, so thewithWhatvariable in both functions point to the same address.If an upvalue of the inner function refers to a local variable of the enclosing function, lua attempts to find the corresponding upvalue from the list of created upvalues in the current stack, it will create a new one if the find fails. (See luaF_findupval)
This is the case with your first piece of code.
withWhatis a variable of themakeAdderfunction and an upvalue of thefunction(a)function, so lua will create a new upvalue for thefunction(a)function to storewithWhat.If you have another function inside the
makeAdderfunction that uses thewithWhatvariable, lua will reuses the created upvalue. Consider the code: