Upvalue order and _ENV

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

Upvalue order and _ENV

Dennis Fischer
For one of my projects I need to reliably change the environment of a function*
While doing some experimenting to see how this could best be done in a way
that works in both LuaJIT and 5.3, I came across the following behavior:

Lua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio
> do
>> local l = 20
>> function test()
>> return l, _ENV
>> end
>> end
> test()
20      table: 007e18b0
> load(string.dump(test), '', 'b', _ENV)()
table: 007e18b0 nil

As you can see, if a normal upvalue is used before any "global" variable, _ENV
is not the first upvalue. While the reference manual doesn't really state that
_ENV has to be the first upvalue, the load function does seem to assume this
and while digging through the archive, there was another thread where everyone
seemed to be taking it for granted that _ENV is always the first upvalue.

Is this supposed to behave like this, or is it a bug? It seems that this
behavior completely defeats the purpose of the load function, as a it completely
breaks for functions like the following:

local original = true
function broken()
if original then
 print "I am the original"
else
 print "I was dumped and re-loaded"
end
end

The intended behavior shouldn't need explanation, but in reality, when dumping
and re-loading this function, it would throw an "attempt to index nil" error.

As for my tests: I have tried this on Lua 5.3.4 on windows, compiled with mingw.
I have also tried it on the online demo at https://www.lua.org/cgi-bin/demo and
the result was the same.

* background: I am trying to achieve an HTML generation syntax similar to that
used in the Lapis framework. This means that I need to pass a new environment
to a function that is provided by the user and, while I can assume that the
function makes use of _ENV, I cannot know if it uses some upvalue first.


Reply | Threaded
Open this post in threaded view
|

Re: Upvalue order and _ENV

Luiz Henrique de Figueiredo
> For one of my projects I need to reliably change the environment of a function*

One of the best ways to ensure that is to use _ENV in the list of parameters:

function process(_ENV, a, b, c)
...
end

Then just call process(myenv,1,2,3) and all globals in process will be
resolved in myenv.

Reply | Threaded
Open this post in threaded view
|

Re: Upvalue order and _ENV

Andrew Gierth
In reply to this post by Dennis Fischer
>>>>> "Dennis" == Dennis Fischer <[hidden email]> writes:

 Dennis> As you can see, if a normal upvalue is used before any "global"
 Dennis> variable, _ENV is not the first upvalue. While the reference
 Dennis> manual doesn't really state that _ENV has to be the first
 Dennis> upvalue,

_ENV is guaranteed to be the first (and only) upvalue if what you're
loading is a text chunk, or a binary that is a dumped chunk (e.g. from
luac) and _not_ a dumped function.

If you load a binary that's dumped from a (non-chunk) function, then
figuring out the upvalues is basically up to you.

--
Andrew.

Reply | Threaded
Open this post in threaded view
|

Re: Upvalue order and _ENV

Roberto Ierusalimschy
In reply to this post by Dennis Fischer
> For one of my projects I need to reliably change the environment of a function*
> While doing some experimenting to see how this could best be done in a way
> that works in both LuaJIT and 5.3, I came across the following behavior:
>
> [...]
>
> As you can see, if a normal upvalue is used before any "global" variable, _ENV
> is not the first upvalue. While the reference manual doesn't really state that
> _ENV has to be the first upvalue, the load function does seem to assume this
> and while digging through the archive, there was another thread where everyone
> seemed to be taking it for granted that _ENV is always the first upvalue.
>
> Is this supposed to behave like this, or is it a bug? [...]

There was a recent discussion about this topic in the list, starting
with

  http://lua-users.org/lists/lua-l/2018-08/msg00111.html

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: Upvalue order and _ENV

Roberto Ierusalimschy
> > For one of my projects I need to reliably change the environment of a function*
> > While doing some experimenting to see how this could best be done in a way
> > that works in both LuaJIT and 5.3, I came across the following behavior:
> >
> > [...]
> >
> > As you can see, if a normal upvalue is used before any "global" variable, _ENV
> > is not the first upvalue. While the reference manual doesn't really state that
> > _ENV has to be the first upvalue, the load function does seem to assume this
> > and while digging through the archive, there was another thread where everyone
> > seemed to be taking it for granted that _ENV is always the first upvalue.
> >
> > Is this supposed to behave like this, or is it a bug? [...]
>
> There was a recent discussion about this topic in the list, starting
> with
>
>   http://lua-users.org/lists/lua-l/2018-08/msg00111.html

See also

  http://lua-users.org/lists/lua-l/2011-10/msg00110.html

-- Roberto