[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: function kidnapping
- From: "John Belmonte" <jvb@...>
- Date: Mon, 8 May 2000 12:07:11 +0900
Given some variable definitions in the global scope
n = 55
function func(x)
return n * x
end
Lua allows us to move such variables to a table using the language's
reflexive facilities or manually:
t = {}
t.n = n
t.func = func
n = nil
func = nil
However t.func() cannot be used as is, because it's still trying to access n
from the global space instead of table t. The problem can be solved by
wrapping the function in an object that will temporarily switch global
accesses to table t. This can be implemented using tag methods. Roughly
the "function" tag method for the wrapping object would look like this:
-- Assuming tag methods in place to allow swapping of global table via
-- a function "setglobaltable".
function wrapper(func, ...)
local oldtable = setglobaltable(t)
local val = call(func, arg)
setglobaltable(oldtable)
return val
end
Once a function is wrapped in this way, it will always run in the context of
table t, even if it is passed around and used as a function object. For
example:
function test()
local funcobj = t.func
print(funcobj(10)) --> 550
end
Although the concept is simple, being able to control the context of a
function gives us a lot of power. Essentially it is a namespace.
Namespaces can be used to implement modules and classes, and closures.
I haven't worked through an implementation yet. Assuming an implementation
is indeed feasible here are some ideas & issues to explore:
* Easy modules: The techique allows us to take code that wasn't written
as a
module (that is, in the global space) and move it into a module
* Closures: We can use this for closures in function objects instead of
accesing an outer table via upvalues
* Assignment issues: Say the following function is wrapped in a
context:
function func(x)
save = x
save2 = x
end
What if we want "save" to mean the actual global space and not the local
context? Python faces this issue also, which is the reason for the
"global"
keyword. It would be trivial to emulate Python's solution using a
functional
interface:
function func(x)
global("save")
save = x -- global
save2 = x -- local context
end
I think a better solution is to always be explicit about the local
context using
some special table. (The fact that Python doesn't do this is an
annoying
inconsistency. Why must we be explicit with "self" for a class but not
explicit
for a module?)
function m.func(x)
save = x -- global
m.save2 = x -- local context
end
* Efficiency: If the wrapping looks inefficient, the tag methods can be
implemented on the C side to speed things up. By the way, imagine that
Python
creates a context like this not just for every function, but for every
block...
that is why it's variable lookups are slow.
-John