« May 2008 | Main | August 2008 »

June 2008 Archives

June 3, 2008

What an excellent idea...

A dynamic language works great when you have a clearly-defined structure of an application, where you know where everything lives, where everything is, and what everything is around you. For example, with a Rails application, you have a very strict structure: You have controllers and views and models, and so on. It's all very uniform. You can easily jump into any place of the application and understand what's around you: Here comes the model, and here's the data from the Web request, and so on. That's easy to figure out. [Dmitry Jemerov via Artima]

...hmmmmm. What an excellent idea. Smithers... the hounds are sleeping? Then release the Falcons! err, actually release the Cougars... wait. Hawks, Cougars, Hawks, Cougars. Meh. Release Both!

June 10, 2008

More than I wanted to know about groovy.lang.Closure

Mind you, I'm not going to tell you everything there is to know about Groovy's implementation of Closures. The principal reason being I don't know that much. For the most part I really like Groovy's closures, because they just magically work and I don't have to worry about adding final to externally referenced variables under threat of compilation error. But there comes a time when making a feature work like magic that you just have to know the details of the magical incantation.

It started out innocently enough, with Andres Almiray coming to me at JavaOne 2008 and suggesting the next great idea for the SwingBuilder: make the bind node work with closures. Well, at least well behaved closures. Because sometimes terseness adds more to readability and usability than rigor does. Consider these two lines, which would you prefer to code and read?

label(text: bind(source:model, sourceProperty:'value'))
label(text: bind {model.value})

Certainly, it should be the second line. Immediately my head started to churn, and my first impression was 'is there some way we can make AST Transformations do this?' Because (a) the first beta of 1.6 had just gone out with AST Transformations making it's debut and (b) this seemed like a compile time problem. But quickly things came screeching to a halt. You see the problem is that in Groovy all method calls and property references are dynamic. Meaning that they go through the Meta-Object Protocol (MOP) to dispatch the call or resolve the value of the property. And the actual methods used to resolve these values can be completely altered at runtime (with the right permissions). This presents a problem with compile time transformations: how do you safely do a transformation on a symbol that may not mean what you think it means at compile time? The short answer is you don't. (The longer answer is deserving of another blog post).

So how can I bind to a somewhat arbitrary closure, one who's meaning isn't fully resolved until runtime? The answer is to use the same mechanisms the closure uses at runtime to resolve it's values, but make a mockery of it instead. Err.. I mean.. use the mock object pattern. This is actually where I started to learn more about the incantations of closures than I intended.

In Groovy, each closure creates a separate type, whose name is a mechanical mangling of the owning type: <Class Name>$_run(_closure<number>)+ and each of these types extends groovy.lang.Closure. However, a closure needs to get some access to the methods and properties of the scope in which it was declared and/or in which it is executed. To this end, it has an owner field, which is always set to the instance it was created in, and a delegate field which can be set to any old object. The resolveStrategy property on the closure is then used to determine which of the fields to use and the order to address them in to resolve methods and properties not directly know to the closure. This was simple enough, since I already exploit that knowledge to get any of the builders to work their magic in the first place. However, once I got the simple case working, the real magic of closures made itself manifest: lexically scoped variables. Consider this script:

String bar = "long"
def closure = { [bar.length(), baz.length()] }
bar = "longer than long"
closure.delegate = [bar:"short", baz:"short"]
println closure()

What will the result be? Wait for it.... is it [4, 5], [5, 5], or [16, 5]? The correct answer is, of course the last one. But how can that be? In Java with an inner class I would be forced to declare bar final, and remove the third line since I cannot alter it, so in Java the first answer would almost always be true. But to get the second answer instead of the third one I would have to remove the typedeclaration for bar, and this is the point where I started to see some of the deep magic at work. Whether or not bar is defined as a free variable or a lexically scoped variable is an essential distinction for a Closure. Properties are not lexically scoped variables, and lexically scoped variables are not pushed through the MOP for resolution like properties are. Lexically scoped variables basically have a static meaning, even when used in a closure that may leave scope. (note: the variables themeselves are not subject to the MOP, but the methods or properties on said variable, those are subject to being MOPed up).

So when Groovy compiles a closure and generates bytecodecode it looks over the lexically scoped variables it can see, and compares it against the symbols that the closure is using. When it encounters a variable that is used by the closure it does two things, first it adds to the closure an argument in the constructor, a field, and a getter method to access the variable within the class. Java does this for Inner classes so it is not too shocking. But the second thing it does, which is simple but powerful, is it wraps all access to the variable in the enclosing scope and in the closure inside of a groovy.lang.Reference object. The code looks like it may be accessing an Object on the stack, but the compiler alters those calls for you so you are actually accessing the reference object and using get and set to read and write to the variable. This allows the variable to, in essence, outlive the stack frame it was created in and for other closures to act on the variable in a manner that can be shared across other closures. Consider this slight alteration...

String bar = "long"
def closure = { [bar.length(), baz.length()] }
bar = "longer than long"
def change = {bar = "Doh" }
closure.delegate = [bar:"short", baz:"short"]
println closure() // [3,4]

Providing an alternate value in the delegate still has no effect, but altering it's value inside another closure does affect it. Knowing this I could now create a separate instance of the Closure and fully mock it up against both lexically scoped variables and free variables in an equivalent fashion. The simple act of adding a type to a previously unbound variable will now no longer break things in strange and mysterious ways. Making things work like magic made me learn more than I ever expected to know about how Groovy implements Closures.

About June 2008

This page contains all entries posted to ... And They Shall Know Me By My Speling Errors in June 2008. They are listed from oldest to newest.

May 2008 is the previous archive.

August 2008 is the next archive.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33