0

I have some lua code in a file. I want to create multiple closure instances of this code, each with a different _ENV upvalue. I can use luaL_loadfile to load the file and set the first upvalue, N times with different tables, to create N instances. But wouldn't this load and compile the file N times?

The lua equivalent of what i want to do is the following, except without the loadfile

func_list = {}

for i = 1, 10 do
    local new_env = {hello=i, print=print}
    func_list[i] = loadfile("Code.lua", "t", new_env)
end

for i = 1, 10 do
    func_list[i]()
end

------ Code.lua ------
print(hello*hello)

is there a better way to do this?

z33m
  • 5,993
  • 1
  • 31
  • 42

2 Answers2

1

Use the IO libraries to load the file into a string, and then call loadstring on it.

Alternatively, just get one chunk and then change it's env prior to executing it

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • if i use `loadstring` it'll compile the code everytime, right? – z33m Jun 11 '12 at 06:04
  • @z33m: Yes, but at least you won't have to perform the I/O. There is no way to duplicate a Lua chunk after it has been compiled. – Puppy Jun 11 '12 at 10:30
1

Whenever you load a string/file in Lua, what you get in return is a function to call to actually run the file. What load does for you is just some additional processing to set the _ENV.

However, nothing prevents you from setting _ENV yourself. You could do it with something like this:

-- Code.lua --
_ENV = ...
print(hello * hello)

Then, you could load/compile the file just once, and use multiple instances as such:

local code = loadfile("Code.lua")

env_list = {}
for i = 1, 10 do
    local new_env = {hello=i, print=print}
    code(new_env)
    env_list[i] = new_env
end

If you do not want the user to write _ENV = ... in every file, you could instead load the file into a string, prepend the line yourself and use load to compile the source. But this would not work on compiled files.

Michal Kottman
  • 16,375
  • 3
  • 47
  • 62
  • did you mean `code(new_env);func_list[i] = new_env` in the for loop. – z33m Jun 11 '12 at 09:53
  • Also, instead of appending `_ENV = ...` to the code. DeadMG 's suggestion should also work right? ie. setting the first upvalue to new_env before executing the chunk – z33m Jun 11 '12 at 09:55
  • Thanks for the comment, I fixed that. Regarding the second question - you could use [this implementation of `setfenv` for Lua 5.2](http://lua-users.org/lists/lua-l/2010-06/msg00313.html) to get what you want. Just notice that now you only have one closure, which changes its environment, instead of multiple closures. – Michal Kottman Jun 11 '12 at 20:28
  • this is fine since im only interested in the functions inside `code.lua`. Each time we call `code`, different closures are created and added into the environment table that we created. So even though we have only one `code` closure, each environment will have separate closures for the functions inside `code.lua`. We can create multiple closures if we wrap the whole code in `code.lua` inside an anonymous function and then return it. so `code(new_env)` will give us a closure that uses new_env as it _ENV. – z33m Jun 12 '12 at 06:35