What is the peculiarity of the global variable _G?

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?

+6
source share
1 answer

How special is the _G global variable?

This is in a special way in three ways:

  • It uses the name reserved for internal use by Lua .
  • It is created by one of the standard Lua modules (in particular, "base" ). If you create a new lua_State without opening the "base" module, you will not have the _G variable. The standalone interpreter has already loaded the standard libraries, though.
  • Some third-party Lua modules use the global variable _G and changing / deleting may violate these modules.

What is the point of _G ?

Global variables in Lua are implemented using a regular table. Any access to a variable that is not a local variable, or an upvalue value will be redirected to this table. Local variables always take precedence, so if you have a global variable and a local variable with the same name, you will always get a local one. And here _G comes _G : If you want a global variable, you can say _G.name instead of name . Assuming that the name _G not a local variable (it is reserved for Lua, remember ?!), this will always give you the value of the global variable using table indexing syntax and thus eliminating ambiguity using local variable names. In newer versions of Lua (5.2+), you can also use _ENV.name as an alternative, but _G precedes these versions and is saved for compatibility.

There are other cases when you want to take over a global table, for example. to set the metatetable. Lua allows you to customize the behavior of tables (and other values) by setting the metatetable using setmetatable , but you must pass the table as a parameter somehow. _G will help you with this.

If you added a meta-furniture to the global table, in some cases you can bypass the metamethods ( __index and / or __newindex ) that you just installed. You can use rawget and rawset , but you need to pass the global table table as a parameter as well.

Note that all the precedents above apply only to Lua code, not to C. In C code, you do not have local variable names, only stack indexes. Therefore, there is no ambiguity. And if you need a reference to the globals table to go to some function, you can use lua_pushglobaltable (which uses the registry instead of _G ). As a result, modules implemented in C do not use / need the _G global variable. This refers to the standard Lua library (which is implemented in C). In fact, the reference guide ensures that _G (a variable, not a table) is not used by Lua or its standard library.

How does _G relate to _ENV ?

Since version 5.0 Lua allows you to modify the table used to search for global variables based on the per- (Lua-) function. In Lua 5.0 and 5.1, you used the setfenv function (a table of global tables also called the "functional environment", hence the name setfenv ). Lua 5.2 introduced a new approach using a different variable name _ENV . _ENV not a global variable, although Lua ensures that every piece starts with _ENV upvalue. The new approach works by allowing Lua to translate any access to the nonlocal (and non-upvalue) variable name a to _ENV.a . Regardless of the fact that _ENV is at this point in the code, it is used to solve global variables. This method is much safer because you cannot change the environment of code that you yourself do not write (without using the debug library), as well as more flexible, because you can change the environment for individual blocks of code by creating local _ENV variables with limited areas.

However, in any case, you will need the default environment, which is used before the programmer has the opportunity to install the user one (or if the programmer does not want to change it). When launched, Lua creates this default environment (also called the "global environment" ) for you and stores this in the registry . This environment is used by default as _ENV upvalue for all chunks, unless you pass user environments for load or loadfile , lua_pushglobaltable also extracts this global environment directly from the registry, so all C-modules automatically use it to access global variables.

And if the standard “base” C-module was loaded, the “global environment” by default has a table field called _G , which refers to return to the global environment.

Summarizing:

  • The global variable _G is actually _ENV._G .
  • _ENV not global, but an upvalue or local variable.
  • The _G field _G by default, "global environment" indicates the global environment.
  • _G and _ENV refer to the same table by default (global environment).
  • C code is also not used, but a field in the registry (which again points to a global environment by definition).
  • You can replace _G (in a global environment) without breaking C or Lua itself (but you can break third-party Lua modules if you are not careful).
  • You can replace _ENV whenever you want, because it only affects your own code (current piece / file no more).
  • If you replace _ENV , you yourself can decide _G ( _ENV._G ) will be available in the affected code, and what this indicates.
+5
source

All Articles