Excerpt from Lua 5.3 Guide :
_G
A global variable (not a function) that contains the global environment (see clause 2.2). Lua itself does not use this variable; a change in its value does not affect any medium, or vice versa.
The relevant part of §2.2
[...] each piece is compiled into the volume of an external local variable named _ENV , so _ENV itself is never a free name in a piece.
[...]
Any table used as the value of _ENV is called an environment.
Lua maintains a dedicated environment called the global environment. This value is stored in a special index in the C registry. In Lua, the global variable _G initialized with the same value. ( _G never used internally.)
When Lua loads a piece, the default value for its _ENV upvalue is a global environment. Therefore, by default, free names in Lua code refer to entries in the global environment
I understand that for each piece loaded, since _ENV will be the first upvalue, it will point to the global environment table, denoted by _G on load .
> =_G, _ENV table: 006d1bd8 table: 006d1bd8
confirms that both point to the same table. The manual states that it is repeated several times that _ENV and _G are just regular names with no hidden meaning and that Lua itself does not use it internally. I tried this piece below:
local a = { } local b = a -- since tables are objects, both refer to the same table object print(a, b) -- same address printed twice a = { } -- point one of them to a newly constructed table print(a, b) -- new, old table addresses printed
Now do the same with _G and _ENV :
local g = _G -- make an additional reference print(g, _G, _ENV) -- prints same address thrice local p = print -- backup print for later use _ENV = { } -- point _ENV to a new table/environment p(g, _G, _ENV) -- old, nil, new table: 00ce1be0 table: 00ce1be0 table: 00ce1be0 table: 00ce1be0 nil table: 00ce96e0
If _G is the usual global, why does it become nil here? If link counting is complete, _G still holds the link at _ENV . Like b above, it should also hold onto the old table, no?
However, for the next fragment, _G not changed / saved!
_ENV = { _G = _G } _G.print(_G, _ENV, _ENV._G) -- old, new, old
But here he is killed:
_ENV = { g = _G } _ENV.g.print(_ENV, _ENV.g, _G) -- new, old, nil
Another case when it persists:
print(_G, _ENV) -- print same address twice local newgt = {} -- create new environment setmetatable(newgt, {__index = _G}) -- set metatable with _G as __index metamethod _ENV = newgt -- point _ENV to newgt print(_G, newgt, _ENV) -- old, new, new
With so many changes in _G behavior _G initial assurance given by the management seems unstable. What am I missing here?