lua-users home
lua-l archive

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


Following Wim and Roberto's comments about (possible) problems with the new
globals system I am trying to clarify my understanding. Please feel free to
correct me and/or add comments. Why do we need (or want) this new system of
globals rather than those of Lua4?


Globals relate to direct accesses to non-local names inside a Lua (and
possibly C) function. The "global table" that is expected to be affected is
either defined (a) by the calling time environment or (b) by something
defined at closure time. These two cases seem to be quite distinct in
nature.


There seems to be three common uses of globals with regard to functions...

(1) To enforce the 'functional' behaviour of a closure. Ie, an untrusted
function call that claims to not alter the global environment might be
explicitly checked, although in practice this is rather hard to police. You
can make sure that the function does not directly alter any of the global
variables (as shown below) but to stop deeper alterations (eg, "x.y = 1"
versus "x = 1") is rather difficult (both under the Lua4 and Lua5 systems).

To stop the a function from altering top level globals one can create a
wrapped version [in this example the function "globals()" reads & sets the
general globals like in Lua4]:

  function secure(f)
    -- Setup a globals table that passes through reads but traps writes.
    local g = {}
    setmetatable(g, {
      __index=function(i) return globals()[i] end,
      __newindex=function(i,v) error("Global write") end,
    })

    -- Create & return a proxy function that wraps the real function
    -- with the special globals.
    return
      function(...)
      local globals = globals
      local unwrap = unwrap
      local og = globals(g)
      local res = f(unwrap(arg))
      globals(og)
      return unwrap(res)
      end
  end

  -- Example of use
  fred = secure(untrusted_fred)


(2) Set at _closure creation time_ to create a local static space. But in
Lua5 we now have lexical scoping so we can easily simulate a local space,
indeed we can have many. Eg:
  do
    local g = {} -- Static space

    function f()
      g.a = 1 -- Set a 'global' variable in that static space.
    end

  end


If you are worried that currently available global definitions (like "print"
etc) might disappear before the function is called, then copy them into one
of those lexically local tables.

If you want a special 'default' table then just temporarily override
globals:
    local globals,og = globals, globals(g)
    -- blah
    globals(og)


(3) Set at _function calling time_ to catch changes.
In this case altering of the closure's globals (as per Lua5 "setglobals")
would be Very Bad, as it is extremely non-recursive / reentrant. The
standard Lua4 tradition is:
    local globals, og = globals, globals(g)
    -- blah
    globals(og)

If you wish this to apply only for a single function call, then you can
create a call wrapper:
  function ecall(g,f,...)
    local globals = globals
    local unwrap = unwrap
    local og = globals(g)
    local res = f(unwrap(arg))
    globals(og)
    return res
  end

  -- Sample usage
  x = ecall({}, fred, 1, 2) + 4


Conclusion:
So far I can't see a need for the new system. What am I missing?


*cheers*
Peter Hill.