R – how to get the closure in lua

closureslua

suppose i have a file name "test.lua" containing lines below:

--[[  test.lua --]]
local f = function()
  print"local function f in test.lua"
end

f_generate = function()
  local fun = loadstring(" f()")
-- local env = getfenv(1)
-- set(fun,env)
  return fun
end
f_generate()()
--[[ end of test.lua--]]

because loadstring doing its stuff under the global environment, so when i call
f_generate()()
i will get an error "attempt to call global 'f' (a nil value)"

the code commented out shows that function environment can't deal with this problem.

cause table is the only data structure in lua, (and function environment and other lots of thing are implement by table), i think is reasonable to assume that the closure are also implement by table, but how can i get it?

Best Solution

From the question as asked and the sample code supplied, I don't see any need for using loadstring() when functions and closures are first-class values in the language. I would consider doing it like this:

-- test.lua 
local f = function()
  print"local function f in test.lua"
end

f_generate = function()
  local fun = function() return f() end
  return fun
end
f_generate()()
-- end of test.lua

The motivation is clearer if there is a parameter to f_generate:

-- test.lua 
local f = function(y)
  print("local function f("..y..") in test.lua")
end

f_generate = function(name)
  local fun = function() return f(name) end
  return fun
end
f_generate("foo")()
f_generate("bar")()
-- end of test.lua

Going through the parser with loadstring() explicitly takes the code outside the scope of the call to loadstring(). Local variables are not stored in any environment table. They are implemented much the same way they would be in any other language: storage for them is allocated by the code generator and is not accessible outside that compilation. Of course, the debug module (and API) has the ability to peek at them, but that is never recommended for use outside of a debugger.

The correct way to preserve a reference to a local for use outside the scope is as a true upvalue to a closure. That is what is achieved by fun = function() return f() end. In that case, the value f is retained as an upvalue to the function stored in fun. Note that in practice, this wrapping as an upvalue is quite efficient. No name lookup is needed to find the value, and since I used a tail-call, no extra stack frames are required either.

Related Question