lua-users home
lua-l archive

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


On Mon, Aug 11, 2014 at 11:08 AM, Steven Degutis <sbdegutis@gmail.com> wrote:
> This is the other part that confused me:
>
>    _ENV is the "global scope"
>
> What does that mean? In the PiL^3 book, it says something similar, but
> instead of _ENV = _G, it says _ENV = <global environment> which made
> me think it was doing a special per-entry copy into a new table or
> something.
>
> So I guess it was how _ENV is populated that I was actually confused
> about this whole time, and still am.

_ENV, unlike _G, does have one additional piece of magic: The language
uses it when it can't find any other definition of a variable.

So suppose you have the following code:

local a
a = 1
b = 2

When this code starts executing, _ENV will be prepopulated by the
language's standard library -- functions like type and print.

When it's done, it'll contain that, plus b, which will have the value
of 2. The first assignment, "a = 1", will first look for a local named
"a", and it finds one, so it uses it. But the second one, "b = 2",
will look for a local named "b", fail to find it, and then look for
one in _ENV. It won't find it there either, so it'll create a new key
in the _ENV table named "b", and assign the value of 2 to it.

If this code is in a file or string that was loaded by something else
(for example, if you require'd a file or loadstring'ed a chunk of
code) then its _ENV will also contain anything that was put into _ENV
before it was created.

But _ENV isn't always the same table -- you CAN assign a new table to
it, and every chunk has its own _ENV. By default, the chunk's _ENV
defaults to the _ENV of its creator (take note: the creator, not the
caller).

So here's some brief demonstration (though I haven't run this for testing):



-- Keep track of the original ENV
local oldenv = _ENV

-- We have to hold on to this, because loadstring is in _ENV
local oldloadstring = loadstring

-- Set up a base case for demonstration
x = 1
print(x) -- outputs 1

-- Replace _ENV, create a new chunk
_ENV = {}
local mychunk = oldloadstring("x = 3")
-- mychunk's _ENV is a reference to the table we just created

-- Demonstrate the behavior
print(x) -- outputs nil
mychunk()
print(x) -- outputs 3

-- Put our original _ENV back
_ENV = oldenv
print(x) -- outputs 1

-- Observe that the new chunk has a different _ENV
mychunk()
print(x) -- still outputs 1



I hope I've been able to demystify things a bit. It took me a while to
grok it myself; Lua 5.1's setfenv() seemed more intuitive to me until
I really poked at the mechanics of _ENV, and now I see that _ENV has
its advantages.

/s/ Adam