lua-users home
lua-l archive

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



On Mar 27, 2015, at 9:05 PM, Sean Conner <sean@conman.org> wrote:

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 about
changing 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