  lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

• Subject: Re: [Suggestion] Sharing local variables with "load"-ed functions
• From: Sean Conner <sean@...>
• Date: Sun, 25 Oct 2015 19:58:04 -0400

```It was thus said that the Great Egor Skriptunoff once stated:
> On Sun, Oct 25, 2015 at 8:29 PM, Patrick Donnelly <batrick@batbytes.com>
> wrote:
>
> > The existing functionality (debug.upvaluejoin) is all you need to do
> > what you want:
> >
> > - Declare locals to be exported:
> >
> > local x = 1
> > export("x", function() return x end) -- **
> > local y = 2
> > export("y", function() return y end)
> >
> > - hook the load function which creates locals with the names of the
> > exported locals and then joins them to the loaded chunk, something
> > like:
> >
>
> Patrick, thanks for the idea!
> It is quite workable, albeit rather anti-aesthetic due to exporting new
> function body for every local:
>   local a, b, c = 1, 2, 3
>   export("x", function() return a end)
>   export("y", function() return b end)
>   export("z", function() return c end)
>   local f = load_with_upvalues("print(x + y + z); x, y, z = x+1, y*2, z^3")
> Compare with this nice-and-easy thing I wanted:
>   local a, b, c = 1, 2, 3
>   local f = load_with_upvalues(@a, @b, @c, "upvalue x, y, z; print(x + y +
> z); x, y, z = x+1, y*2, z^3")

One thing to keep in mind---chunks are functions.  So the following does
work:

CODE1 = [[
local x = select(1,...)
local y = select(2,...)
local z = select(3,...)

return function() return x,y,z end
]]

f1 = load(CODE1,"code1","t",{select = select})("one",2,true)
print(f1())

This works to get external values into the locals of a chunk, but it
doesn't solve the issue of sharing upvalues among different chunks.  I have
noticed that despite this:

Upvalues have no particular order, as they are active through the
whole function. They are numbered in an arbitrary order.

that upvalues are numbered in a consistent order---the order they are
defined in (whether you can depend on this is another matter, but I've found
this to be true for Lua 5.2 and Lua 5.3), so this also works:

CODE1 = [[ local x,y; return function() return x,y end ]]
CODE2 = [[ local x,y; return function() return x,y end ]]

f1 = load(CODE1,"code1","t",{})()
f2 = load(CODE2,"code2","t",{})()

debug.upvaluejoin(f1,1,f2,1)
debug.upvaluejoin(f1,2,f2,2)

debug.setupvalue(f1,1,14)
debug.setupvalue(f2,2,"hello")

print(f1())
print(f2())
print()

as does this:

function load_with_upvalues(code,join,...)
local f = load(code)()

if join then
local info = debug.getinfo(join)
for i = 1 , info.nups do
debug.upvaluejoin(f,i,join,i)
end
else
for i = 1 , select('#',...) do
local v = select(i,...)
debug.setupvalue(f,i,v)
end
end

return f
end

CODE1 = [[ local x,y; return function() return x,y end ]]
CODE2 = [[ local x,y; return function() return x,y end ]]

f1 = load_with_upvalues(CODE1,false,14,"hello")
f2 = load_with_upvalues(CODE2,f1)

print(f1())
print(f2())
print()

-spc

```