[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Nested funcs and "upvalues"
- From: Roberto Ierusalimschy <roberto@...>
- Date: Fri, 31 Oct 1997 12:38:44 -0200
> 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