lua-users home
lua-l archive

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


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