lua-users home
lua-l archive

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

I'm still curious about how closures are actually handled.  Function parameters and function locals are not members of _ENV, I understand function parameters live on the stack and I assume space for function locals is allocated on a heap of some kind maintained by the interpreter. It must have the following properties:

1) When a closure occurs some of these objects are given persistence because they are referred to by the newly defined function. 

2)  Further these upvalues can grow since a table can be an upvalue and a function with a table as an upvalue can add to it.

3) If two closures refer to the same local variable or function parameter they each have a reference to the same storage location.

My question is when a function is defined does the interpreter parse the new function to determine what values of the defining function become persistent as part of the closure or does all the local storage of the defining function get preserved as a package?  To clarify: in this bit of code:

function f(fpar)
	local f1 = 1111111111
	local f2 = 22222
	local f3 = 33333
	local f4 = {'imagine this is a table that uses lots of storage'}
	function g() print('in g', fpar, f1, f2) end
	function h() print('in h', fpar, f1, f3) end

g() and h() both have shared access to fpar and f1 (and if one of them changed one of these upvalues the other would see it.)

g() has access to f2 but not f3 and visa versa for h()

I assume that f4 went out of scope when f() exits and will be collected but if a closure saves all of the local storage of a defining function this might not be the case and f4 might persist until both g and h went out of scope. 

That is what I mean by parsing the defined functions.  When g() and h() were defined did the interpreter look to see which local variables of f() they used and mark each variable appropriately?

If so I assume the usual rules about garbage collection of any memory that no longer has a reference to it apply.  That is g = nil will cause collection of f2 but not f1 or f3.  

Further if g() had a statement like f1 = f2 then h() would gain access to the location pointed to by f2 and g = nil would no longer cause collection of that memory.

On Apr 1, 2012, at 2:58 AM, Dirk Laurie wrote:

>>> 1)  Globals live in a table called _G, any function has a variable called _ENV which is the same table unless I explicitly redefine it in which case for that function's life globals are whatever is in the table pointed to by _ENV.  (_G and DEFAULT_ENVIRONMENT you  mentioned are the same thing?)
>> I'm personally not a fan of referring to _G as a specific object, but yes.
> Not quite.
> 1. Globals live in whatever table is currently associated with the name
> _ENV.
> 2. Whenever you enter a function, Lua has pre-initialized _ENV
> for you, so that _ENV and _ENV._ENV are the same.
> 3. _G is a key in the original _ENV.  The only special thing
> about _G is that Lua initializes _ENV._G to _ENV right at the
> start.
> 4.  Lua never again changes or refers to _G.  It's there for
> your convenience only.
> 5. If you never muck about with _ENV or _G, Lua automatically
> provides an _ENV in which _ENV._G (i.e. _G) still refers to the
> original global environment
> Let's execute some code in which _ENV is modified.
> Lua 5.2.0 (alpha)  Copyright (C) 1994-2010, PUC-Rio
>> print(_ENV,_G); _ENV=nil; print(_ENV,_G)
> table: 0x9fb13b0	    table: 0x9fb13b0
> stdin:1: attempt to index upvalue '_ENV' (a nil value)
> After `_ENV=nil`, there is no _G anymore until _ENV is redefined,
> for example by returning from the current function.
>> _G=nil; f=function(_ENV) print(_G) end;
>> f(_ENV)
> nil
>> f{print=print,_G="ha-ha!"}
> ha-ha!
> If you supply your own _ENV, you must do something like that
> `print=print`, or providing a suitable __index metamethod, if
> you will need access to routines in the standard library.