By “extent” I mean, how long do local variables exist?
In languages such as C, C++, and Java, local variables are destroyed as soon as you leave the scope in which they’re declared. If a function or method has a local variable, each time you call it, you get a different variable with the same name each time. In C and C++ you can try to do stuff like reusing the variable without initializing it, or returning its address, but the results of doing so are undefined and give incorrect programs.
C++ provides for somewhat stronger behavior for local variables that are objects, in that the object’s constructor is called when the scope is entered and the destructor is called when the scope is exited.
Java has similar rules, but the abstraction is much stronger. You can’t take the address of a local variable, nor can you attempt to use a local variable before initializing it — it’s a compiler error. You can try to “hang on” to a local variable by using it within an anonymous class, but the language requires that such locals be declared final. (I’m not entirely sure why; I think it allows the implementation to copy the value somewhere else so that all the locals in the method scope can be destroyed.)
In JavaFX, local variables can hang around for an arbitrary length of time. One way of doing this is by creating an inner function that references the outer function’s local variable. This creates a “closure,” that is, a closed environment that contains the local variables that are in scope at the time of the inner function’s creation. JavaFX has had closures for quite some time; Jim Weaver wrote a nice article about this over a year ago. Here’s a denser example:
function f(p: Integer): function(): Integer {
var localvar = p;
function(): Integer {
++localvar;
}
}
What the heck does this do? First, f is a function that takes an integer and returns a function-that-returns-an-integer. This inner function (which has no name) increments the local variable and returns its new value. (Note that I had to copy the parameter into a local, since in JavaFX function parameters cannot be modified.) Now let’s call f a couple times, and then call each of the returned functions a couple times.
var g = f(17);
var h = f(32);
println("g() => {g()}");
println("h() => {h()}");
println("g() => {g()}");
println("h() => {h()}");
The output is:
g() => 18 h() => 33 g() => 19 h() => 34
(Astute readers will find this discussion reminiscent of the first chapter of Abelson & Sussman.) What’s going on here is that the first call to f created a local variable and a function that captured it, and returned this new function. This function was stored in g. The second call to f created a different local variable and a different function and returned it, and this was stored in h.
It’s not clear whether the functions “really” are different. The compiler might generate and use the same code for them, but they definitely use different environments. If you compare g and h you’ll find that they are not equal. Indeed, calling them gives different results. As you can see from the output, they clearly contain different instances of the local variable localvar. What’s more, these two instances of localvar exist long after f has returned. And they’ll continue to exist for as long as you hold onto g and h.
But inner functions aren’t the only way that local variables can continue to exist after their enclosing function exits. The bind and trigger (“on replace”) language constructs can also extend the lifetime of local variables. More on that in my next post.
Update: next post is here.