lua-users home
lua-l archive

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


Thanks so much I appreciate the effort to explain this.  To check my understanding again:

1) The copying of upvalues to the place they remain and the creation of the pointer that the defined function inherits is a task of the interpreter and there is no visible table where they live.

2) I take it the scope of upvalues is the life of all functions that inherited them.  That is if I were to create a large local table say and then created some functions that inherited it the storage the table used would not be garbage collected until any variables that held the addresses of the functions with that table as an upvalue went out of scope.  (And the only way a global variable goes out of scope is setting it to nil.)

I still do not understand where upvalues live but apparently I can just assume the interpreter takes care of them in some way Lua code does not have to worry about.

I did test whether upvalues are shared by different functions.  The code snippet:

function f()
	print'in f'
	local fvar = 'f'
	print(fvar)
	function g()
		print('in g fvar =', fvar)
		fvar = 'g'
		print('after setting fvar in g fvar = ', fvar)
		return fvar
	end
	function h()
		print('in h fvar =', fvar)
		fvar = 'h'
		print('after setting fvar in h fvar = ', fvar)
		return fvar
	end
end

produces:
> f()
in f
f
> g()
in g fvar =	f
after setting fvar in g fvar = 	g
> =g()
in g fvar =	g
after setting fvar in g fvar = 	g
g
> h()
in h fvar =	g
after setting fvar in h fvar = 	h
> =g()
in g fvar =	h
after setting fvar in g fvar = 	g
g
> 

This tells me that there is a single upvalue fvar that is shared by g() and h().  I assume it will persist until both g() and h() go out of scope.  It is also not visible outside of g() or h().  I also notice that f = nil does not cause fvar to disappear nor does setting g to nil.

Out of curiosity is there any way to access or change an upvalue like fvar outside of any functions that own pointers to it?  It appears to me that if not upvalues  would be a useful way to have private variables in objects.  An object generating function could create the storage for private variables and the method functions and then return a table of methods which was the object.  Since the private data was an upvalue of the method functions it would be accessible only through them.


On Mar 31, 2012, at 2:56 PM, Peter Cawley wrote:

> On Sat, Mar 31, 2012 at 7:29 PM, Jose Torre-Bueno <jtorrebueno@cox.net> wrote:
>> Thank you;
>>  let me paraphrase to make sure I understand:
>> 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.
> 
> On Sat, Mar 31, 2012 at 7:29 PM, Jose Torre-Bueno <jtorrebueno@cox.net> wrote:
>> 2) Local variables live on the stack which is managed by the interpreter and I don't have any special access to them except through the names of the variables.
> 
> Yes.
> 
> On Sat, Mar 31, 2012 at 7:29 PM, Jose Torre-Bueno <jtorrebueno@cox.net> wrote:
>> 3) Upvalues are stored when a function is defined.
>> 
>> This leaves the question where are upvalues stored?  Is it in a table like _G or some hidden place?
>> 
>> Also you mention sharing of upvalues, does this mean sharing of the values or the names? That is if a function defines two new functions they both see the local variables of the creating function as upvalues my question is if one of the new functions changes an upvalue does the other see the change or does each have a private copy of its upvalues?  For that matter if a function creates another and then calls the created function while the creating function is still in scope can the created and called function change the value of a local of the calling function?
> 
> Upvalues and intimately tied to closures, and both of these are subtle
> concepts. Perhaps they are best explained by examples, so let us begin
> with a simple 6 line example:
> 
> local x
> function set_x(value)
>  x = value
> end
> set_x(4)
> print(x) --> 4
> 
> To understand this, you need to appreciate that the 2nd line isn't
> defining a function called set_x, but instead creating a function
> object and assigning it to set_x. To emphasize this point, I've
> rewritten the above code using fictional syntax for function objects
> (closures), which look like tables, but are created with angle
> brackets rather than curly brackets:
> 
> local x
> set_x = <
>  parameters = "value",
>  code = "x = value",
>  x = the local variable defined 4 lines prior,
>> 
> set_x(4)
> print(x) --> 4
> 
> In the above, the upvalue part is `x = the local variable defined 4
> lines prior` (I could have said that the upvalue x refers to the local
> variable x, but that would be slightly less clear). This example
> extends to the general case; all upvalues begin their lives as
> pointers to an active local variable (*). Whenever a local variable
> goes out of scope, a copy of it is made, and all upvalues which used
> to point to the local variable are updated to point to the copy.
> 
> (*) The exception to this is when creating a function object which
> inherits an upvalue from the enclosing function object; in this case
> the new upvalue begins its life as a pointer to whatever the old
> upvalue was pointing to. In particular, it may be pointing to an
> aforementioned copy. As an example of this phenomenon, consider the
> following 10 line piece of code:
> 
> do
> 	local x
> 	function outer()
> 	  function set_x(value)
> 	    x = value
> 	  end
> 	end
> end
> outer()
> set_x(4)
> 
> The closure called outer has an upvalue which initially refers to the
> local, and is subsequently updated to refer to a copy of the local.
> When outer is called, it creates a new closure called set_x, which
> inherits the upvalue from outer. Again, this may be clearer with the
> fictional function object syntax:
> 
> do
> 	local x
> 	outer = <
> 	  parameters = "",
> 	  x = the local variable defined 3 lines prior,
> 	  code = [[
> 	    set_x = <
> 	      parameters = "value",
> 	      x = the upvalue defined 4 lines prior,
> 	      code = "x = value",
> 	    >,
> 	  ]],
> 	>
> end
> outer()
> set_x(4)
> 
> This example exposes a useful point: when an upvalue is created, it
> can only be one of two things:
> 1) A copy of an upvalue of the calling function
> 2) A pointer to an active local variable of the calling function
> 
> Hence when you write code in which a function refers to a local
> variable which is more than one function "above" it, all of the
> intermediary functions gain an upvalue.
> 
> Hopefully that is the full and complete story of how upvalues and
> closures work, and perhaps it is clear enough to assist in gaining an
> understanding of how they work.
>