lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Thu, Feb 25, 2010 at 1:40 PM, Jonathan Castello wrote:
> On a related note, could loadstring/loadfile be modified slightly to
> load into the currently active environment, rather than their own
> environment? If they continue to refer to the original global
> environment, then I can't really allow sandboxed code to use them
> unless I replace them with my own versions. It seems like a fairly
> harmless change, unless people are relying on the load-always-in-_G
> behavior.

Some of us have not liked the behavior of `load` and its variants
applying the global environment `_G` when the current environment is
not `_G` [1,2].  Some years ago, I suggested making these function
instead apply the environment of the caller [1].  However, as Sergey
Rozhenko reminds me [3], this doesn't always give us the desired
behavior either; consider:

  function one() return pcall(loadstring, s) end

Here, the "caller" is not `one` but rather `pcall`, which has an
environment of `_G`.  Granted, this problem would be at least reduced
if the function `pcall` were replaced with an actual keyword in the
language, as John Belmonte et al have been advocating [4,5], but I
don't think that alone addresses the real problem here.  Utilizing the
"environment of the caller", or any call stack levels, is really a
type of dynamic scoping, and we should ask whether that is really what
we want.  (The Lua `module` function does likewise, and I'm glad that
aspect is deprecated in 5.2 [6].)  Dynamic scoping in the form of
tying environments to call stack frames, as Mark Hamburg suggested
[10], may avoid the above problem since `pcall` would no longer have
the environment `_G`, but let's ignore that for now.

So, if Lua were to apply neither `_G` nor the environment of the
caller, what would it apply?  I think a reasonable design is for
`load` and its variants to default the environment to `nil` unless an
environment is explicitly given as an argument.  One such argument is
the current lexical environment (`_ENV`), which in the current Lua 5.2
proposal must be explicitly given.  The Lua-5.2.0-work2 `loadin`
function roughly follows that design, but the other functions like
`loadfile` still apply `_G`, limiting their reuse.

  function one() return pcall(loadin, _ENV, s) end

~~~

Note the effect that the `_ENV` proposal would have if Lua supported a
C-like "include" statement, or if we just run the C preprocessor over
Lua:

  local _ENV = module(...)
  function one()
    #include "foo.lua"
  end

This program would be equivalent to copying and pasting the contents
of the file "foo.lua" into the given location, which implies that
foo.lua would see its parent's environment.  In fact, it could access
*all* its parent's local variables, which `loadin` cannot do, at least
not without explicitly passing them as well or using hacks with
`debug.getlocal`.  Similar things may be said about other compile-time
metaprogramming situations [7-9].

[1] http://lua-users.org/wiki/DofileNamespaceProposal
[2] http://lua-users.org/lists/lua-l/2008-05/msg00552.html
[3] http://lua-users.org/wiki/SandBoxes
[4] http://lua-users.org/wiki/ResourceAcquisitionIsInitialization
[5] http://lua-users.org/lists/lua-l/2009-01/msg00333.html
[6] http://lua-users.org/lists/lua-l/2010-02/msg00811.html
[7] http://lua-users.org/wiki/StringInterpolation
[8] http://lua-users.org/wiki/CodeGeneration
[9] http://lua-users.org/wiki/MetaProgramming
[10] http://lua-users.org/lists/lua-l/2010-01/msg01484.html