[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Lua 5.0 and globals (long)
- From: "Peter Hill" <corwin@...>
- Date: Sun, 2 Mar 2003 04:27:56 +0800
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.