Reputation: 23
This is a question about closures in Lua. I stumbled across a problem (and workaround) while trying to make an object registrar object as follows:
tracker = {
objList = {},
myRegister = function(self, obj)
table.insert(self.objList, obj)
return "hello"
end,
myInit = function(self)
local i, obj
for i, obj in ipairs(self.objList) do
obj:init()
end
end,
}
-- Note: As written, this does *not* work.
-- It *will* work if I separate the line into two parts as follows:
-- local myvar
-- myvar = tracker:myRegister({
local myvar = tracker:myRegister({
init = function(self)
-- This will generate an error complaining that myvar
-- is a global variable with a "nil" value
print("myvar = " .. myvar)
end,
})
tracker:myInit()
It seems that if I declare the local variable, "myvar", in the same statement which creates a closure, then the local variable is not accessible from the closure. If, however, I merely assign to an already-existing local variable, then that variable is accessible from the closure.
Obviously, I know how to fix this: Just declare myvar separately.
My question, however, is this: Why is this necessary? Is this by design, or is it a bug in the compiler and/or virtual machine? If it's by design, where is it documented? I'm particularly interested in whether this behavior has other implications, and what those might be, and I'm hoping that the documentation (again assuming this is the intended behavior) will shed some light on this.
Upvotes: 2
Views: 152
Reputation: 23727
Yes, this is the intended behavior.
It is documented in the Lua manual §3.5 – Visibility Rules
This feature allows you to write the following code:
print"Beginning of log"
do
local print =
function(...)
print(os.date"%T", ...) -- Here you're invoking global "print"
end
-- inside this do-end block "print" is automatically adding current time
print"Some event"
print"Another event"
end
print"End of log"
In other words, while the shadowing object is being created, the original object is still accessible.
This is quite useful.
Upvotes: 1