[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Explanation needed for setfenv replacement for Lua 5.2
- From: "E. Toernig" <froese@...>
- Date: Wed, 4 May 2011 19:30:00 +0200
Lorenzo Donati wrote:
>
> I need some help in understanding some Lua code Sergey Rhozenko posted a
> while ago. They are two version of 'setfenv' to use with upcoming Lua
> 5.2 in order to replace the missing library function.
I just hope, that people using such code know what they do.
But anyway ...
> The lines that I don't understand are those where debug.upvaluejoin is
> called. Why is this call needed? Isn't debug.setupvalue enough?
>Version 1:
> if name then
> debug.upvaluejoin(f, up, function() return name end, 1)
> debug.setupvalue(f, up, t)
> end
Version 2:
> if name then
> debug.upvaluejoin(f, up, function() return t end, 1)
> end
The 2nd is just an optimization of the first. Some background:
Upvalues are heap objects that hold values. They can be shared between
functions. setupvalue changes the value the upvalue holds. All functions
sharing that upvalue will see that change:
local x=1
function a() return x end
function b() return x end
debug.setupvalue(a, 1, 42)
print(a(), b()) --> 42 42
Here a and b share a single upvalue that is created for x. If you
modify the value of the upvalue for "a" (via setupvalue), you will
at the same time change the value "b" will see.
On the other hand, upvaluejoin does not modify the value of an upvalue
but replaces the actual upvalue:
local x=1
local y=2
function a() return x end
function b() return y end
debug.upvaluejoin(a, 1, b, 1)
print(a(), b()) --> 2 2
y=42
print(a(), b()) --> 42 42
Here, a's first upvalue (x) is replaced by b's first upvalue (y) so
both now reference y.
Back to the setfenv emulation. The first version
> debug.upvaluejoin(f, up, function() return name end, 1)
> debug.setupvalue(f, up, t)
creates a dummy function with one new upvalue (for name) and transfers
this upvalue to f. In the next step it sets the value of this new
upvalue to t.
The 2nd version
> debug.upvaluejoin(f, up, function() return t end, 1)
starts the same, but makes sure, the new new upvalue already holds the
correct value (t). So the second step is no longer needed.
With that background, one can see that there are usually better ways
to handle the environment in Lua 5.2 - especially if you want to
modify the env for a handful of functions:
--8<--
global = "global"
do
local _ENV = _ENV
function demo_setenv(t) _ENV = t end
function demo1() print("demo1", global) end
function demo2() print("demo2", global) end
end
demo1() --> demo1 global
demo2() --> demo2 global
demo_setenv{print=print, global="private"}
demo1() --> demo1 private
demo2() --> demo2 private
demo_setenv(_ENV)
demo1() --> demo1 global
demo2() --> demo2 global
--8<--
I.E. if you want to change the env for a complete module just add a simple
setenv function to its module table and be done:
function M.setenv(t) _ENV = t end
Ciao, ET.
PS: I still not sure if a "function environment" is The Right Thing.
I would prefer a simple thread-wide "setglobals" ;-)