[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: _ENV vs _G
- From: Coda Highland <chighland@...>
- Date: Mon, 11 Aug 2014 11:48:08 -0700
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