How special is the global variable _G?
<p>Excerpt from <a href="http://www.lua.org/manual/5.3/manual.html#pdf-_G" rel="noreferrer">Lua 5.3 manual</a>:</p>
<blockquote>
<h3>_G</h3>
<p>A global variable (not a function) that holds the global environment (see §2.2). Lua itself does not use this variable; changing its value does not affect any environment, nor vice versa.</p>
</blockquote>
<p>Relevant part from §2.2</p>
<blockquote>
<p>[…] every chunk is compiled in the scope of an external local variable named <code>_ENV</code>, so <code>_ENV</code> itself is never a free name in a chunk.</p>
<p>[…]</p>
<p>Any table used as the value of <code>_ENV</code> is called an environment.</p>
<p>Lua keeps a distinguished environment called the global environment. This value is kept at a special index in the C registry. In Lua, the global variable <code>_G</code> is initialized with this same value. (<code>_G</code> is never used internally.)</p>
<p>When Lua loads a chunk, the default value for its <code>_ENV</code> upvalue is the global environment. Therefore, by default, free names in Lua code refer to entries in the global environment</p>
</blockquote>
<p>I understand that for every chunk loaded, since <code>_ENV</code> would be the first upvalue, it is <em>pointed to</em> the global environment table, pointed by <code>_G</code> by <code>load</code>.</p>
<pre><code>&gt; =_G, _ENV
table: 006d1bd8 table: 006d1bd8
</code></pre>
<p>confirms that both point to the same table.  The manual states, rather reassures multiple times, that <code>_ENV</code> and <code>_G</code> are just regular names with no hidden meaning and that Lua itself doesn't use it internally.  I tried this chunk below:</p>
<pre><code>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
</code></pre>
<p>Now doing the same with <code>_G</code> and <code>_ENV</code>:</p>
<pre><code>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
</code></pre>
<p>If <code>_G</code> is an ordinary global, why is it becoming <code>nil</code> here?  If reference counting is done, <code>_G</code>, was still holding a reference at the time <code>_ENV</code> released it.  Like <code>b</code> above, it too should be holding on to the old table, no?</p>
<p>However, for the below chunk, <code>_G</code> is unchanged / preserved!</p>
<pre><code>_ENV = { _G = _G }
_G.print(_G, _ENV, _ENV._G)   -- old, new, old
</code></pre>
<p>But here it is killed:</p>
<pre><code>_ENV = { g = _G }
_ENV.g.print(_ENV, _ENV.g, _G)    -- new, old, nil
</code></pre>
<p>Another case where it is preserved:</p>
<pre><code>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
</code></pre>
<p>With so many variations in the behaviour of <code>_G</code>, the original reassurance given by the manual seems shaky.  What am I missing here?</p>