How special is the global variable _G?

How special is the global variable _G?

It is special in three ways:

  1. It uses a name reserved for internal use by Lua.
  2. It is create by one of Lua's standard modules (in particular the "base" module). If you create a fresh lua_State without opening the "base" module, you won't have the _G variable. The standalone interpreter has all standard libraries already loaded, though.
  3. Some third-party Lua modules use the global variable _G, and changing/removing it can break those modules.

What's the point of _G?

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

There are other cases where you want to get a hold of the globals table, e.g. for setting a metatable. Lua allows you to customize the behavior of tables (and other values) by setting a metatable using the setmetatable function, but you have to pass the table as a parameter somehow. _G helps you do that.

If you have added a metatable to the globals table, in certain cases you might want to circumvent the metamethods (__index and/or __newindex) you've just installed. You can use rawget and rawset, but you need to pass the globals table as a parameter as well.

Note that all the use-cases listed above only apply to Lua code not C code. In C code you don't have named local variables, only stack indices. So there is no ambiguity. And if you want a reference of the globals table to pass to some function, you can use lua_pushglobaltable (which uses the registry instead of _G). As a consequence, modules implemented in C don't use/need the _G global variable. This applies to Lua's standard library (which is implemented in C) as well. In fact, the references manual guarantees, that _G (the variable, not the table) is not used by Lua or its standard library.

How does _G relate to _ENV?

Since version 5.0 Lua allows you to change the table used to look up global variables on a per-(Lua-)function basis. In Lua 5.0 and 5.1 you used the setfenv function for that (the globals table is also called "function environment", hence the name setfenv). Lua 5.2 introduced a new approach using another special variable name _ENV. _ENV is not a global variable though, Lua makes sure that every chunk starts with an _ENV upvalue. The new approach works by letting Lua translate any access to a non-local (and non-upvalue) variable name a to _ENV.a. Whatever _ENV is at that point in the code gets used to resolve global variables. This way is a lot safer because you can't change the environment of code you didn't write yourself (without using the debug library), and also more flexible because you can change the environment for individual blocks of code by creating local _ENV variables with limited scopes.

However, in any case you need a default environment that is used before the programmer has a chance to set a custom one (or if the programmer does not want to change it). On startup, Lua creates this default environment (also called "global environment") for you and stores it in the registry. This default environment is used as the _ENV upvalue for all chunks unless you pass custom environments to load or loadfile. lua_pushglobaltable also retrieves this global environment directly from the registry, so all C modules automatically use it for accessing global variables.

And if the standard "base" C module has been loaded, this default "global environment" has a table field called _G that refers back to the global environment.

To sum it up:

  • The global variable _G is actually _ENV._G.
  • _ENV is not a global, but an upvalue or a local variable.
  • The _G field of the default "global environment" points back to the global environment.
  • _G and _ENV by default refer to the same table (said global environment).
  • C code doesn't use either, but a field in the registry (which again points to the global environment by definition).
  • You can replace _G (in the global environment) without breaking C modules or Lua itself (but you might break third-party Lua modules if not careful).
  • You can replace _ENV whenever you want, because it only affects your own code (the current chunk/file at most).
  • If you replace _ENV, you can decide for yourself whether _G (_ENV._G) will be available in the affected code, and what it points to.