lua-users home
lua-l archive

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


> Ah, I see. This is "late binding" with a vengance! Will it be efficient
> enough for practical use, with every call to f() re-creating the nested
> unnamed function?

  The implementation uses two structures, which we have called "closure" and
"proto". The "proto" keeps the static description of a function (bytecode,
debug information, etc; in short, everything but the upvalues), and it is
created once when the function is compiled (like in Lua 3.0). Then only
the closure (a small record with a reference to the proto and the upvalues)
is re-created when f() re-creates the nested function; all these closures
refer to the same proto. Therefore, the cost to create a new instance of a
function is smaller than the cost to create a table.

  Notice that, unlike other languages such as Scheme, these closures are
created only when a new function is *created*, not when it is called.
Therefore, programs that do not use nested functions will have a completely
negligible overhead (the creation of a single closure for each function it
declares). 


> I'm not sure why this is a problem. Here, you appear to be returning the
> result of a function declaration as the result of the outer function.
> What's the problem with making this an error, or at least making it
> nil by convention. Surely the unnamed function is a local of f()?

  First it is difficult to detect such "errors", since functions are first
class values. Consider:

    function f(x)
      local a = function (y) return x+y end   -- 'a' is local, so access to x
                                              -- is safe...
      ...
      g(a);  -- use OK
    end

    function g(x)
      global1 = x  -- how to detect this?
    end

  Second, and more important, there are many useful things we can do
when we are able to return nested functions with a proper environment
(that is, the "unnamed function" *not* being local). As a small example,
the following function creates "counters":

    function newcounter()
      local t = {n=0}
      local f = function () %t.n=%t.n+1; return %t.n end
      return f
    end

    c1 = newcounter(); c2 = newcounter();
    print(c1())  -- prints 1
    print(c1())  -- prints 2
    print(c2())  -- prints 1
    print(c1())  -- prints 3
    ...

  Each call to 'c1' returns a new integer, the same for 'c2', but both are
completely independent from each other (and the counter variables themselves
are completely "protected" inside the closures).

  For a much more powerful example, see:

    "Haskell vs. Ada vs. C++ vs. Awk vs. ... An Experiment in Software
      Prototyping Productivity." by Paul Hudak & Mark Jones.
     (ftp://nebula.systemsz.cs.yale.edu/pub/yale-fp/papers/NSWC/jfp.ps) 

-- Roberto