lua-users home
lua-l archive

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


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.