In my previous entry, I mentioned that binds and triggers could extend the lifetime of local variables. This is incorrect. I think what’s really happening is that local variables aren’t destroyed immediately when their defining scope exits; they can continue to live for an arbitrary period of time. In a language like Java, you cannot observe anything about a local variable after its scope has exited, since there’s no way to name it or to create a reference to it. So, you can’t tell whether the variable has been destroyed immediately or whether it sticks around. However, in JavaFX Script, you can observe a local variable after its scope has exited. Consider the following example.
var v = 0; function f(p: Integer):Void { var localvar = bind p + v on replace old { println("localvar: {old} => {localvar}"); } } f(17); f(32); println(">>> increment v"); v++; println(">>> increment v again"); v++; println(">>> done!");
If you compile and run this program, the output is:
localvar: 0 => 17 localvar: 0 => 32 >>> increment v localvar: 17 => 18 localvar: 32 => 33 >>> increment v again localvar: 18 => 19 localvar: 33 => 34 >>> done!
(Note that the trigger fires the first time, when the variable is initialized from its default value of zero to the value of the expression in its initializer.)
Like the previous example, this shows that there are two distinct local variables named localvar that have been created by the two calls to function f. Normally after f returns, there’s no way to observe localvar. However, since it’s been initialized to a bind-expression that uses an external variable (v in this case), we can change its value by manipulating that external variable. Furthermore, we can observe changes to the value by attaching a trigger (“on replace”) expression that has the side effect of printing a message. Pretty cool, eh?
Well, maybe. The problem is that although we can observe localvar by placing a trigger on it, there is nothing external that references it. This seems pretty fragile, since things that don’t have references to them are subject to being garbage collected. Let’s test this by allocating a bunch of memory to force GC. Just before “increment v again” insert the following code:
var seq: String[]; for (i in [1..50000]) { insert "{i}" into seq; }
(Your mileage may vary. On my system, a loop of 50,000 causes GC every time.) If you run the program again, the output is as follows:
localvar: 0 => 17 localvar: 0 => 32 >>> increment v localvar: 17 => 18 localvar: 32 => 33 >>> increment v again >>> done!
What just happened? This is quite odd. In Java, the only way to observe anything about an object is to have a reference to it, and having a reference will prevent it from being collected. In JavaFX Script, we can place a trigger on a local variable in order to observe changes to its value, and we can change its value by virtue of having initialized it with a bind-expression. But we don’t actually have any references to it, so the variable, the bind-expression, and the trigger are all subject to garbage collection!
This is admittedly a pretty obscure corner of the language. Why would anybody want to put a bind and a trigger on a local variable? In my next blog post, I’ll explain why this construct has come up repeatedly in real programs, how the GC issue has caused problems, and what to do about it.
UPDATE: followup post is here.
Huh!
Thanks for sharing this. I guess this is either a bug in the language implementation or even in the specification (should local variables allowed?)
To me it’s clearly a hole in the language. It’s hard to say whether it’s a bug in the compiler or runtime implementation, since this area isn’t really well specified.
See http://javafx-jira.kenai.com/browse/JFXC-2168 .
I’ll have more to say about this in an upcoming blog post.
Why i get the following output with ? (4times (f(x))
localvar: 0 => 17
localvar: 0 => 32
localvar: 0 => 44
localvar: 0 => 86
>>> increment v
localvar: 17 => 18
localvar: 32 => 33
>>> increment v again
localvar: 33 => 34
>>> done!
..Only two lines after “>>>increment v” is this because garbage collection ?
again about results after calling 4times (fx) ..
I have created a new, empty, javafx file and now i get the right output (4lines at beginning, 4lines after >>>increment v and 4 lines after >>>increment v again.
Ieksss… i have been copy/pasting and now everything works well.
I was working with an Stage file and had copy the code into that source. Now i have again copy the code into that source and now it goes well.
Strange…
(Sorry about the delay in approving these comments. WordPress didn’t notify me that they were pending.)
I don’t have much of an explanation as to why in the first case you got 4, then 2, then 1 line of output, whereas in the second case you got 4 lines of output each time.
I don’t think it has anything directly to do with whether there is a Stage active in the script.
I’m fairly certain that the reason the results are unpredictable is because of garbage collection. As far as your program is concerned, GC can occur anytime, and it’s almost completely out of your control. GC might occur at different times from one run to the next.
So, there’s really no good explanation as to why this kind of program behaves one way or another. It really is unpredictable. The best thing to do is simply to avoid this construct.