lua-users home
lua-l archive

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


It was thus said that the Great Dirk Laurie once stated:
> 2015-03-28 6:05 GMT+02:00 Sean Conner <sean@conman.org>:
> 
> >   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.
> 
> First, let's explain _ENV.

  [ snip ]

> Now when you change _ENV, in whatever way, the original global
> environment is invisible unless you have in some way kept it. E.g.

  Yes, I know all this.  You still haven't explained upvalues though.

  Okay, now that I've thought about this, I think I know how upvalues are
actually implemented.  You define a local variable, some space is set aside
to store values:

			+------+
	location X:	| _ENV |
			+------+

			+------+
	location Y:	| BOB  |
			+------+

  Now, let's create two functions that reference this variable:

		function foo(x)
		  _ENV.print(BOB + x)
		end

		function bar(x)
		  return _ENV.tostring(BOB - x)
		end

  Each function has an upvalue for _ENV and BOB.  These upvalues are
pointers [1] to the actual variables:

		foo
			upvalue 1	location X -- illustrative purposes
			upvalue 2	location Y -- only

		bar
			upvalue 1	location Y
			upvalue 2	location X

  When you call debug.setupvalue(), say:

		debug.setupvalue(foo,2,99)

it stores the 99 in location Y, that being the location of the variable
storing the upvalue in slot 2 of foo.  So of course, when you change the
upvalue for _ENV, you are not changing the location of the upvalue but the
location that upvalue is pointing to.  So doing

		debug.setupvalue(bar,2,{ })

updates location X with an empty table, which in this case, is not only the
environment for foo, but probably the global environment.  The upvalue 2 for
bar hasn't changed, as it's still pointing to location X, but location X has
changed!

  I think what caught me up is that I haven't really played with Lua 5.2 (or
Lua 5.3 until a few days ago) and I was still kind of expecting the Lua 5.1
behavior with setfenv(), which is a "local" change of a function's
environment, and not the global change that happens now (because upvalues
are pointers).

  -spc (So now that I've explained it to me like I was five, I think I'm
	done here)

[1]	Sorry for the Cism here, but that's how I have to think about this.