• Announcement: Lua.org now officially recommends this forum as a meeting place for the Lua community

How works _G and _ENV and what can I do with them? (1 Viewer)

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
76
Reaction score
9
I'm curious to know how they work and the information I found isn't enough so I need a better explanation and also wanna know what can I do with them because I see the programs that use Lua use them to create their global values.
 

GavinW

Newcomer
Creator of RiscLua
Joined
Oct 21, 2020
Messages
54
Reaction score
20
Age
83
Location
UK
Website
www.wra1th.plus.com
Herly, I recommend that you buy Programming in Lua (Fourth Edition) by Roberto Ierusalimschy, if you do not yet have it. You won't regret it. Chapter 22 (The Environment) is what you need. All variables in Lua are either keys in a table or are local to a chunk. So-called global variables are just keys in _ENV. Every chunk comes with a local variable called _ENV. Remember that the whole program is a chunk, the global chunk. All variables in a chunk that are not local to it, or local to a surrounding chunk, are looked up in the table given by that chunk's _ENV. This means that you can use _ENV to simplify your syntax. I don't think that you can do anything in your program with _ENV that you could not do without it, perhaps more clumsily. [This is an invitation to others to rush in and show that I am wrong.]
 

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
76
Reaction score
9
@GavinW I don't know, because I'm not much about reading long texts even if I'm interested in the topic, I do that but is too difficult to me, so I'm not sure in invest 27$ in a book (100 PEN in my country).
 

stetre

Member
Rank: II
Joined
Jan 8, 2020
Messages
103
Reaction score
58
Location
Italy
Website
github.com
You can think of _ENV as a table that implicitly holds your global variables. For example, try running the lua shell and executing the following in it (here the > is the shell prompt):

Lua:
> x = "this is x"
> print(_ENV.x)
> _ENV.x = "this is _ENV.x"
> print(x)

You'll see that the value of _ENV.x is the value you assigned to x, and viceversa. This is because x and _ENV.x are the same thing.

That is, x is not really a 'global' variable but it's actually a field of the table _ENV. You don't have to refer to it as _ENV.x though (but you can if you want to) because Lua automatically understands that you are referring to _ENV.x if there is no local variable with the name x in scope.

The table _ENV is called the environment, which (my guess) is short for the environment where the code is executed in. This gives you a hint on what it can be used for: to create separate environments where to execute different scripts or chunks of code, so that (for example) they can use the same names for 'global' variables without stepping on each other's feet. Or to sandbox them, by providing them an environment with limited functionalities (for example you may not want them to use the io library, so you would provide an _ENV without it).

The table _G is the global environment, which you can think of as the default _ENV. Another experiment you can do in the Lua shell is this:

Lua:
> print(_G)
> print(_ENV)

You'll see that they are the same table.

Yet another experiment that may be helpful in getting to know _ENV (and/or _G) is to print its contents:

Lua:
> for k, v in pairs(_ENV) do print(k, v) end

You'll see that its fields are the exactly the variables that you are likely accustomed to think of as global variables (including the standard libraries, such as 'math', or the core functions such as 'require' or 'print').

When you're comfortable with all the above, the next step is to read the manual entries for load( ) and loadfile( ), which are the functions you use to execute other Lua code from Lua code. They both accept an optional env parameter, which allows you to customize the environment where to execute the loaded code, giving you the opportunity to do things such as those mentioned earlier (sandboxing and separate environments).
 

Herly Quijano

Newcomer
Joined
Mar 19, 2021
Messages
76
Reaction score
9
You can think of _ENV as a table that implicitly holds your global variables. For example, try running the lua shell and executing the following in it (here the > is the shell prompt):

Lua:
> x = "this is x"
> print(_ENV.x)
> _ENV.x = "this is _ENV.x"
> print(x)

You'll see that the value of _ENV.x is the value you assigned to x, and viceversa. This is because x and _ENV.x are the same thing.

That is, x is not really a 'global' variable but it's actually a field of the table _ENV. You don't have to refer to it as _ENV.x though (but you can if you want to) because Lua automatically understands that you are referring to _ENV.x if there is no local variable with the name x in scope.

The table _ENV is called the environment, which (my guess) is short for the environment where the code is executed in. This gives you a hint on what it can be used for: to create separate environments where to execute different scripts or chunks of code, so that (for example) they can use the same names for 'global' variables without stepping on each other's feet. Or to sandbox them, by providing them an environment with limited functionalities (for example you may not want them to use the io library, so you would provide an _ENV without it).

The table _G is the global environment, which you can think of as the default _ENV. Another experiment you can do in the Lua shell is this:

Lua:
> print(_G)
> print(_ENV)

You'll see that they are the same table.

Yet another experiment that may be helpful in getting to know _ENV (and/or _G) is to print its contents:

Lua:
> for k, v in pairs(_ENV) do print(k, v) end

You'll see that its fields are the exactly the variables that you are likely accustomed to think of as global variables (including the standard libraries, such as 'math', or the core functions such as 'require' or 'print').

When you're comfortable with all the above, the next step is to read the manual entries for load( ) and loadfile( ), which are the functions you use to execute other Lua code from Lua code. They both accept an optional env parameter, which allows you to customize the environment where to execute the loaded code, giving you the opportunity to do things such as those mentioned earlier (sandboxing and separate environments).
Thank you for the explanation.
 

JohnBig

Newcomer
Joined
Feb 9, 2022
Messages
3
Reaction score
0
You can think of _ENV as a table that implicitly holds your global variables. For example, try running the lua shell and executing the following in it (here the > is the shell prompt):

Lua:
> x = "this is x"
> print(_ENV.x)
> _ENV.x = "this is _ENV.x"
> print(x)
When I try to execute this code, I get "attempt to index global '_ENV' (a nil value)".
In case it matters, I'm launching my lua file via bash.
 

stetre

Member
Rank: II
Joined
Jan 8, 2020
Messages
103
Reaction score
58
Location
Italy
Website
github.com
When I try to execute this code, I get "attempt to index global '_ENV' (a nil value)".
In case it matters, I'm launching my lua file via bash.

What matters is the Lua version you're using. _ENV was introduced in Lua 5.2, if I recall correctly.
 

JohnBig

Newcomer
Joined
Feb 9, 2022
Messages
3
Reaction score
0
Thanks for the response. Turns out I'm on Lua 5.1.5 here on my testing device.
But the game I'm programming for is from 2014, so its internal Lua interpreter must have an even older version, and there is no chance of updating that.
I wouldn't have thought that development is still that recent in that area.
 

JohnBig

Newcomer
Joined
Feb 9, 2022
Messages
3
Reaction score
0
I'd like to derive a function call from a string name, preferably with the table being local. This works:
Code:
lookup_tom = {"A", "B"}
name = "tom"
print(_G["lookup_"..name][1])
This does not:
Code:
local lookup_tom = {"A", "B"}
name = "tom"
print(_G["lookup_"..name][1])
 

stetre

Member
Rank: II
Joined
Jan 8, 2020
Messages
103
Reaction score
58
Location
Italy
Website
github.com
As I explained earlier, _G holds the global variables. In the second code, lookup_tom is local so there is no entry for it in _G.

(I'm not sure I understood what you're trying to do. Still, I'd bet there is some way to do it without resorting to _G or _ENV.)
 
Top