_ENV vs _G

classic Classic list List threaded Threaded
46 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Jay Carlson

I have a lot more code using _G than hyperbolic trig. Possibly +inf times more.

On Aug 12, 2014 6:54 AM, "Axel Kittenberger" <[hidden email]> wrote:
Which can simply be circumvented if it wouldn't be there:

local _G = _ENV
local _ENV = setmetatable({}, {__index=_ENV})

function print(...)
    _G.print("my print:", ...)
end

I agree with Dirk, _G ought to be deprecated.


On Tue, Aug 12, 2014 at 12:51 PM, Tom N Harris <[hidden email]> wrote:
On Tuesday, August 12, 2014 09:16:59 AM Dirk Laurie wrote:
> 2014-08-12 8:51 GMT+02:00 Mason Mackaman <[hidden email]>:
> > Also, so far it seems like _G is the equivalent Lua 5.2’s appendix.
>
> Maybe, for the sake of conceptual integrity, it could be deprecated
> in Lua 5.3.

I think it still has a place.

    local _ENV = setmetatable({}, {__index=_ENV})

    function print(...)
      _G.print("my print:", ...)
    end

There are three general scopes that most sensible programs will concern
themselves with: local, file (or module or class), and global. The first has
the `local' keyword, the second has the _ENV upvalue, and the last has _G.

--
tom <[hidden email]>


Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Dirk Laurie-2
2014-08-12 13:51 GMT+02:00 Jay Carlson <[hidden email]>:

> I have a lot more code using _G than hyperbolic trig.
> Possibly +inf times more.

In other words, you have a lot of Lua 5.1 code.

"Conceptual integrity" deals with whether something in older
Lua fits in neatly with current thinking about where Lua is going.
A kind of Occam's razor. I agree with Mason that _G is a mere
evolutionary relic whose presence in the manual is confusing.

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Axel Kittenberger
In reply to this post by Jay Carlson

I have a lot more code using _G than hyperbolic trig. Possibly +inf times more.

sed -i "s/\b[_G]\b/[_ENV]/g" *.lua

This is one kind of doing forward compatibility that is so easy to do. If you need a recursive version:

find -name "*.lua" | xargs sed -i "s/\b[_G]\b/[_ENV]/g"

(I didn't test both so use with coution)

The same with new keywords, I don't get all the complaints about a new keywords, when in fact it is in most times very little to adapt. For example moved C code to be C++ there is for example a new keyword "class", which some code used. Well search/replace with "elementClass" done. Finished in a few minutes...

I know one can construct obscure examples where Lua reflection ability (that is input/output interacts with field names) can disturb things what can't happen in C/C++ but honestly, they are likely to be very rare.

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

steve donovan
On Tue, Aug 12, 2014 at 2:48 PM, Axel Kittenberger <[hidden email]> wrote:
> sed -i "s/\b[_G]\b/[_ENV]/g" *.lua

Ah, but that's not a correct substitution - _ENV starts out as _G, but
may change.  For the idiom where one's doing _G.print in a module with
new _ENV the fix would be the 'local _G = _ENV' at the top that was
suggested.

But really, why?  This mania for deprecation puzzles me.

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Dirk Laurie-2
2014-08-12 14:53 GMT+02:00 steve donovan <[hidden email]>:
> On Tue, Aug 12, 2014 at 2:48 PM, Axel Kittenberger <[hidden email]> wrote:
>> sed -i "s/\b[_G]\b/[_ENV]/g" *.lua
>
> Ah, but that's not a correct substitution - _ENV starts out as _G, but
> may change.  For the idiom where one's doing _G.print in a module with
> new _ENV the fix would be the 'local _G = _ENV' at the top that was
> suggested.
>
> But really, why?  This mania for deprecation puzzles me.

It has been applauded by some, including this [1]:

   It's refreshing to see Roberto talking about what to REMOVE from
   the next version of Lua instead of the feeping creaturism that
   dominates most language development.

[1] http://lua-users.org/lists/lua-l/2014-04/msg00205.html

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Axel Kittenberger
In reply to this post by steve donovan
For a programming language the more answers to questions in the style of "why is this done that way?" the proper answer starts with "this is best explained historically, first there was, then, etc. ..." the more awkward the language becomes as whole.


On Tue, Aug 12, 2014 at 2:53 PM, steve donovan <[hidden email]> wrote:
On Tue, Aug 12, 2014 at 2:48 PM, Axel Kittenberger <[hidden email]> wrote:
> sed -i "s/\b[_G]\b/[_ENV]/g" *.lua

Ah, but that's not a correct substitution - _ENV starts out as _G, but
may change.  For the idiom where one's doing _G.print in a module with
new _ENV the fix would be the 'local _G = _ENV' at the top that was
suggested.

But really, why?  This mania for deprecation puzzles me.


Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Roberto Ierusalimschy
In reply to this post by Tim Hill
> The 5.2 ref manual (section 2.2) states “When Lua compiles a
> chunk it initializes the value of its _ENV upvalue…”. When I
> was initially studying Lua this did confuse me until I realized
> that it really means “When Lua LOADS a chunk…” [...]

Thanks!

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Steven Degutis
This is my current understanding of how _G and _ENV work based on my
reading of the manual and Pil^3 along with Roberto's response to my
first email:

When you create a new Lua state, its registry (i.e. the table at
LUA_REGISTRYINDEX) contains a special table somewhere which is
henceforth known as "the global environment".

When you load a new chunk for Lua to execute, something essentially
equivalent to the following pseudocode happens:

    local _ENV = lua_gettable(L, LUA_REGISTRYINDEX, <global environment's key>)
    _ENV._G = _ENV

That is, _G is a "global" (i.e. a field on the key _ENV) referring to
the initial value of _ENV, which is "the global environment".

As for C code that use lua_getglobal and lua_setglobal, they are
equivalent to operating directly on the table retrieved by doing:

    // assuming temporarily that <global environment's key> is a string:
    lua_pushstring(L, <global environment's key>);
    lua_gettable(L, LUA_REGISTRYINDEX);

Now, ignoring what the type of <global environment's key> happens to
be, is this a correct understanding of how both _G and _ENV are
created?

I am not so much interested to hear about /how/ they behave with other
Lua code, because once I am sure this is how they are created, and
assuming they are using otherwise-normal Lua semantics, it is very
easy to infer how they behave with any Lua code.

On Tue, Aug 12, 2014 at 8:56 AM, Roberto Ierusalimschy
<[hidden email]> wrote:
>> The 5.2 ref manual (section 2.2) states “When Lua compiles a
>> chunk it initializes the value of its _ENV upvalue…”. When I
>> was initially studying Lua this did confuse me until I realized
>> that it really means “When Lua LOADS a chunk…” [...]
>
> Thanks!
>
> -- Roberto
>

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Tim Hill

On Aug 12, 2014, at 8:11 AM, Steven Degutis <[hidden email]> wrote:

> This is my current understanding of how _G and _ENV work based on my
> reading of the manual and Pil^3 along with Roberto's response to my
> first email:
>
> When you create a new Lua state, its registry (i.e. the table at
> LUA_REGISTRYINDEX) contains a special table somewhere which is
> henceforth known as "the global environment".
>
> When you load a new chunk for Lua to execute, something essentially
> equivalent to the following pseudocode happens:
>
>    local _ENV = lua_gettable(L, LUA_REGISTRYINDEX, <global environment's key>)
>    _ENV._G = _ENV
>
> That is, _G is a "global" (i.e. a field on the key _ENV) referring to
> the initial value of _ENV, which is "the global environment”.
>


Read my earlier post. I don’t think the _ENV_G assignment happens when you do a load (after all, this would have the effect of resetting _G after every call to load()). My reading is that setting _G happens ONCE only for the distinguished environment (when the Lua_State is initialized I presume), and never again.

This also means that if you supply your OWN environment table at load() time, it will NOT contain an _G unless you explicitly set it.

—Tim



Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Dirk Laurie-2
In reply to this post by Steven Degutis
2014-08-12 17:11 GMT+02:00 Steven Degutis <[hidden email]>:

> This is my current understanding of how _G and _ENV work based on my
> reading of the manual and Pil^3 along with Roberto's response to my
> first email:
>
> When you create a new Lua state, its registry (i.e. the table at
> LUA_REGISTRYINDEX) contains a special table somewhere which is
> henceforth known as "the global environment".
>
> When you load a new chunk for Lua to execute, something essentially
> equivalent to the following pseudocode happens:
>
>     local _ENV = lua_gettable(L, LUA_REGISTRYINDEX, <global environment's key>)
>     _ENV._G = _ENV
>
> That is, _G is a "global" (i.e. a field on the key _ENV) referring to
> the initial value of _ENV, which is "the global environment".

I don't agree, but I may wrong.

I think it's like this:

1. When you create a new Lua state, you have an empty stack and two tables,
the registry and the global environment. The global environment is empty, no _G
yet, but it behaves like an upvalue called _ENV, so that all
references to global
variables get referred to it. The registry contains two items, [1]
being the current
running thread and [2] being a the global environment.

2. When you call luaL_openlibs, some stuff gets put in the registry.
Into the global
environment go all the standard library items, including _G
initialized to value [2]
from the registry.

3. The standalone Lua interpreter does both the above, so you never see
the intermediate state, but if you write your own host program, you can.

4. If you compile a function using `load` or `loadstring`, its _ENV is one of:
   a. An _ENV parameter.
   b. The _ENV specified in the `load`.
   c. An _ENV upvalue.

Note that _ENV is never global. You can assign anything you like to _ENV._ENV,
it will not be retrieved if you merely say _ENV.

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Tim Hill

On Aug 12, 2014, at 8:48 AM, Dirk Laurie <[hidden email]> wrote:

4. If you compile a function using `load` or `loadstring`, its _ENV is one of:
  a. An _ENV parameter.
  b. The _ENV specified in the `load`.
  c. An _ENV upvalue.

I think it’s always either the distinguished environment (the one stored in the registry at a well-known key) or the explicit table specified as an argument to load().

—Tim

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Sean Conner
In reply to this post by Tim Hill
It was thus said that the Great Tim Hill once stated:

>
> On Aug 12, 2014, at 8:11 AM, Steven Degutis <[hidden email]> wrote:
>
> > This is my current understanding of how _G and _ENV work based on my
> > reading of the manual and Pil^3 along with Roberto's response to my
> > first email:
> >
> > When you create a new Lua state, its registry (i.e. the table at
> > LUA_REGISTRYINDEX) contains a special table somewhere which is
> > henceforth known as "the global environment".
> >
> > When you load a new chunk for Lua to execute, something essentially
> > equivalent to the following pseudocode happens:
> >
> >    local _ENV = lua_gettable(L, LUA_REGISTRYINDEX, <global environment's key>)
> >    _ENV._G = _ENV
> >
> > That is, _G is a "global" (i.e. a field on the key _ENV) referring to
> > the initial value of _ENV, which is "the global environment”.
> >
>
>
> Read my earlier post. I don’t think the _ENV_G assignment happens when you
> do a load (after all, this would have the effect of resetting _G after
> every call to load()). My reading is that setting _G happens ONCE only for
> the distinguished environment (when the Lua_State is initialized I
> presume), and never again.

  _G is only set if you load the base library into the Lua state, either
with luaopen_base() or luaL_openlibs().  Lua itself does not use _G as far
as I can see (checked both 5.1 and 5.2), and I suspect it's there just for
convenience.

  -spc


Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Steven Degutis
In reply to this post by Dirk Laurie-2
This is getting really confusing. So I figured I'd just look in the
source. Here are the relevant chunks of code:

Apparently _G is set inside luaopen_base:
http://www.lua.org/source/5.2/lbaselib.c.html#luaopen_base

It's just doing <env>._G = <env> where <env> is gotten by lua_pushglobaltable.

Here's the definition of lua_pushglobaltable:
http://www.lua.org/source/5.2/lua.h.html#lua_pushglobaltable

It just does lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS).

Pretty straight-forward. For the most part, this is the only instance
of _G in the source-code.

The one other use of _G is in an internal table used by luaL_openlibs:
http://www.lua.org/source/5.2/linit.c.html#loadedlibs

Mystery solved.

-Steven

On Tue, Aug 12, 2014 at 10:48 AM, Dirk Laurie <[hidden email]> wrote:

> 2014-08-12 17:11 GMT+02:00 Steven Degutis <[hidden email]>:
>> This is my current understanding of how _G and _ENV work based on my
>> reading of the manual and Pil^3 along with Roberto's response to my
>> first email:
>>
>> When you create a new Lua state, its registry (i.e. the table at
>> LUA_REGISTRYINDEX) contains a special table somewhere which is
>> henceforth known as "the global environment".
>>
>> When you load a new chunk for Lua to execute, something essentially
>> equivalent to the following pseudocode happens:
>>
>>     local _ENV = lua_gettable(L, LUA_REGISTRYINDEX, <global environment's key>)
>>     _ENV._G = _ENV
>>
>> That is, _G is a "global" (i.e. a field on the key _ENV) referring to
>> the initial value of _ENV, which is "the global environment".
>
> I don't agree, but I may wrong.
>
> I think it's like this:
>
> 1. When you create a new Lua state, you have an empty stack and two tables,
> the registry and the global environment. The global environment is empty, no _G
> yet, but it behaves like an upvalue called _ENV, so that all
> references to global
> variables get referred to it. The registry contains two items, [1]
> being the current
> running thread and [2] being a the global environment.
>
> 2. When you call luaL_openlibs, some stuff gets put in the registry.
> Into the global
> environment go all the standard library items, including _G
> initialized to value [2]
> from the registry.
>
> 3. The standalone Lua interpreter does both the above, so you never see
> the intermediate state, but if you write your own host program, you can.
>
> 4. If you compile a function using `load` or `loadstring`, its _ENV is one of:
>    a. An _ENV parameter.
>    b. The _ENV specified in the `load`.
>    c. An _ENV upvalue.
>
> Note that _ENV is never global. You can assign anything you like to _ENV._ENV,
> it will not be retrieved if you merely say _ENV.
>

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Tim Hill
In reply to this post by Sean Conner

On Aug 12, 2014, at 10:20 AM, Sean Conner <[hidden email]> wrote:


Read my earlier post. I don’t think the _ENV_G assignment happens when you
do a load (after all, this would have the effect of resetting _G after
every call to load()). My reading is that setting _G happens ONCE only for
the distinguished environment (when the Lua_State is initialized I
presume), and never again.

 _G is only set if you load the base library into the Lua state, either
with luaopen_base() or luaL_openlibs().  Lua itself does not use _G as far
as I can see (checked both 5.1 and 5.2), and I suspect it's there just for
convenience.

 -spc

Yep just noticed that. However this still means (as I noted), that _G is set only once (at most) when a Lua state is created. It is NOT set as part of any chunk compile/load.

—Tim

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Tom N Harris
In reply to this post by Axel Kittenberger
On Tuesday, August 12, 2014 12:53:56 PM Axel Kittenberger wrote:
> Which can simply be circumvented if it wouldn't be there:
>
> local _G = _ENV

_ENV is not guaranteed to be the global environment. Your file may be loaded
in a private environment. The point is to reach through the scope tree to the
root that is visible to all parts of the program. (Unless policy doesn't
allow, of course.) Say to redefine a global function such as `type'.

--
tom <[hidden email]>

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Dirk Laurie-2
In reply to this post by Tim Hill
2014-08-12 19:09 GMT+02:00 Tim Hill <[hidden email]>:

>
> On Aug 12, 2014, at 8:48 AM, Dirk Laurie <[hidden email]> wrote:
>
> 4. If you compile a function using `load` or `loadstring`, its _ENV is one
> of:
>   a. An _ENV parameter.
>   b. The _ENV specified in the `load`.
>   c. An _ENV upvalue.
>
>
> I think it’s always either the distinguished environment (the one stored in
> the registry at a well-known key) or the explicit table specified as an
> argument to load().

It's only the one specified in the registry if that still happens to be
the current upvalue called _ENV. And even the one in the registry
may not be the one you started with. You can assign something
to debug.getregistry[2]; not recommended, though.

Here is a little demo. Save it as 'env.lua'; it does not run in the IDE
because of different local scope.

local _ENV = {id="_ENV local to `do` block"}

local function f1() return _ENV, id end
print("case c:",f1())
local _ENV1=_ENV
_ENV = {id="_ENV shadowing previous local variable"}
print("case c:",f1())
print "case c: _ENV is the table currently in this upvalue"
local function f2(_ENV) return _ENV, id end
print("case a:",f2(_ENV1))
print("case a:",f2(_ENV))
print "case a: _ENV is the table passed as argument to the function"
local f3 = load("return _ENV,id",nil,nil,_ENV1)
print("case b:",f3())
local f3 = load("return _ENV,id",nil,nil,_ENV)
print("case b:",f3())
print "case b: _ENV is the table passed as argument to load"
end

$ lua53 env.lua
table: 0x10f85f0    _ENV as in original registry
case c:    table: 0x1100430    _ENV local to `do` block
case c:    table: 0x10fffe0    _ENV shadowing previous local variable
case c: _ENV is the table currently in this upvalue
case a:    table: 0x1100430    _ENV local to `do` block
case a:    table: 0x10fffe0    _ENV shadowing previous local variable
case a: _ENV is the table passed as argument to the function
case b:    table: 0x1100430    _ENV local to `do` block
case b:    table: 0x10fffe0    _ENV shadowing previous local variable
case b: _ENV is the table passed as argument to load

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Dirk Laurie-2
Sorry, the top six lines were not copied.
I'm appending the file.

id="_ENV as in original registry"
local load,print = load,print
local orig_ENV = _ENV
print(_ENV,id)

do

env.lua (1012 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Tim Hill
In reply to this post by Dirk Laurie-2

On Aug 12, 2014, at 1:02 PM, Dirk Laurie <[hidden email]> wrote:

> 2014-08-12 19:09 GMT+02:00 Tim Hill <[hidden email]>:
>>
>> On Aug 12, 2014, at 8:48 AM, Dirk Laurie <[hidden email]> wrote:
>>
>> 4. If you compile a function using `load` or `loadstring`, its _ENV is one
>> of:
>>  a. An _ENV parameter.
>>  b. The _ENV specified in the `load`.
>>  c. An _ENV upvalue.
>>
>>
>> I think it’s always either the distinguished environment (the one stored in
>> the registry at a well-known key) or the explicit table specified as an
>> argument to load().
>
> It's only the one specified in the registry if that still happens to be
> the current upvalue called _ENV. And even the one in the registry
> may not be the one you started with. You can assign something
> to debug.getregistry[2]; not recommended, though.


That’s not my reading of the docs/source, though they are rather unclear.

If you are using load() etc, and you do NOT specify an “env” argument, you will get the distinguished environment (the one in the well-known registry index). Otherwise, the _ENV upvalue of the newly loaded chunk will be set to the specific value supplied by the “env” argument to load(). Any existing value in _ENV in the code calling load(), (regardless of whether it is an upvalue, local, or function argument) is not involved (that is, loaded chunks do not implicitly inherit the environment of the code doing the load()). So, as I said, _ENV for the newly loaded chunk will be either the distinguished environment or an one explicitly supplied as an argument to load().

This certainly appears to be what luaB_load() is doing (the handler for load()).

—Tim


Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Dirk Laurie-2
2014-08-12 23:12 GMT+02:00 Tim Hill <[hidden email]>:

>
> On Aug 12, 2014, at 1:02 PM, Dirk Laurie <[hidden email]> wrote:
>
>> 2014-08-12 19:09 GMT+02:00 Tim Hill <[hidden email]>:
>>>
>>> On Aug 12, 2014, at 8:48 AM, Dirk Laurie <[hidden email]> wrote:
>>>
>>> 4. If you compile a function using `load` or `loadstring`, its _ENV is one
>>> of:
>>>  a. An _ENV parameter.
>>>  b. The _ENV specified in the `load`.
>>>  c. An _ENV upvalue.
>>>
>>>
>>> I think it’s always either the distinguished environment (the one stored in
>>> the registry at a well-known key) or the explicit table specified as an
>>> argument to load().
>>
>> It's only the one specified in the registry if that still happens to be
>> the current upvalue called _ENV. And even the one in the registry
>> may not be the one you started with. You can assign something
>> to debug.getregistry[2]; not recommended, though.
>
>
> That’s not my reading of the docs/source, though they are rather
> unclear.

Have you read my code in env.lua, verified that it gives the specified
results, and checked my logic in claiming why it gives those results?

If not, there is not much point in my trying to argue with you.

Reply | Threaded
Open this post in threaded view
|

Re: _ENV vs _G

Tim Hill

On Aug 13, 2014, at 12:17 AM, Dirk Laurie <[hidden email]> wrote:

>>>>
>>>> 4. If you compile a function using `load` or `loadstring`, its _ENV is one
>>>> of:
>>>> a. An _ENV parameter.
>>>> b. The _ENV specified in the `load`.
>>>> c. An _ENV upvalue.
>>>>
>>>
>>> It's only the one specified in the registry if that still happens to be
>>> the current upvalue called _ENV. And even the one in the registry
>>> may not be the one you started with. You can assign something
>>> to debug.getregistry[2]; not recommended, though.
>>
>>
>> That’s not my reading of the docs/source, though they are rather
>> unclear.
>
> Have you read my code in env.lua, verified that it gives the specified
> results, and checked my logic in claiming why it gives those results?
>
> If not, there is not much point in my trying to argue with you.
>

Indeed I did, though I was discussing and not arguing. Perhaps we are talking about different things. My reading of your post was that a compiled chunk (which is, by definition, a function) could have any of (a), (b) or (c) as it’s _ENV. My point was that this isn’t true, it can only be (b) or the distinguished environment. If, however, you mean that lexically NESTED functions WITHIN a compiled chunk may have (a), (b) or (c) then yes of course that is true as per the Lua documentation.

As I’m sure we both know, compiling this string:

function foo() end

Does NOT leave the function “foo” on the stack (or, in Lua terms, return the function from load), it leaves a function on the stack that, when executed, will add a closure named foo to the current global environment.

—Tim




123