It was thus said that the Great Soni L. once stated: You're changing the _value_ of the upvalue and expecting the _upvalue_ to change...
Then perhaps I have the wrong mental image of how upvalues work in Lua,because it's doing things I don't expect. Okay, explain to me like I'm five how this works. I have the following code: local a = 3 function foo(x) local y = 4 * x + a print(y) return y end foo(3) I run it. I get 15. Okay, let me change the upvalue "a" [1] debug.setupvalue(foo,1,4) foo(3) print(a) And I get 16 (expected) and 4 (also expected). Now, let's see aboutchanging the _ENV on that sucker: debug.setupvalue(foo,2,{ print = print }) foo(3) lua-53: z.lua:16: attempt to call a nil value (global 'foo') stack traceback: z.lua:16: in main chunk [C]: in ? WTF? That is NOT what I expected. Let me think on this …
Upvalues are badly named, which is why the formal Lua docs call them “non-local variables” now. They are indeed variables, but *shared* variables. In your example above, the “a” upvalue is shared between “foo” and the enclosing lexical level (the kinda-sorta “global” level). You can change “a” in either scope and see the change in the other. The same is true for “_ENV” .. it’s not true that each function gets a COPY of _ENV, it’s gets to share the same variable. Hence the issue with nil. So this is not two variables that happen to reference the same table; it’s ONE variable that references a table. So a change at one scope alters the other.
if you want to get the effect you want, declare a local _ENV to over-ride the inherited upvalue _ENV.
—Tim
|