You can learn something every day. That's what is so nice about being a software developer.
Today I was looking at some Grails code, seeing how some of the metaprogramming features of Groovy are used in the framework. After poking around I decided to look at the ServicesGrailsPlugin to see how the automatic wiring of services was done, and ran across the following code:
def doWithSpring = {
application.serviceClasses.each { serviceClass ->
def scope = serviceClass.getPropertyValue("scope")
"${serviceClass.fullName}ServiceClass"(MethodInvokingFactoryBean) {
targetObject = ref("grailsApplication", true)
targetMethod = "getArtefact"
arguments = [ServiceArtefactHandler.TYPE, serviceClass.fullName]
}
def hasDataSource = (application.config?.dataSource || application.domainClasses.size() > 0)
if(serviceClass.transactional && hasDataSource) {
def props = new Properties()
props."*"="PROPAGATION_REQUIRED"
"${serviceClass.propertyName}"(TransactionProxyFactoryBean) { bean ->
if(scope) bean.scope = scope
target = { innerBean ->
innerBean.factoryBean = "${serviceClass.fullName}ServiceClass"
innerBean.factoryMethod = "newInstance"
innerBean.autowire = "byName"
if(scope) innerBean.scope = scope
}
proxyTargetClass = true
transactionAttributes = props
transactionManager = ref("transactionManager")
}
}
else {
"${serviceClass.propertyName}"(serviceClass.getClazz()) { bean ->
bean.autowire = true
if(scope) {
bean.scope = scope
}
}
}
}
}
Reading this with little working knowledge of Grails, but a lot of working knowledge of Groovy I was trying to figure out where "application" was defined. So, I continued to dig, and realized that they are using a Binding instance set on the closure.
This binding defines the properties that the doWithSpring closure "close" over. (Well, it's a little more complicated than that in the Grails code, but that's the idea. See BeanBuilder#getProperty() for the full details.) So, using closures and bindings Groovy provides a very powerful system for creating things, such as Grails plugin system.
So, what is all this talk of closures? What is this binding of which you speak? Let's take an example:
def a = "Hello"
def c = {
println a;
}
c.call()
Here we have a very short Groovy script that def's a String object a, then a closure c, then calls c. When the Closure c is defined the variable a exists and is closed over by the closure, allowing access to the value when it is called.
So, a closure "closes" over the scope in which it is defined, and will remain closed over that scope even if the scope has exited, but we'll get to that later.
What would happen if we reverse the order of a and c in our example?
def c = {
println a;
}
def a = "Hello"
c.call()
We will get the following error:
Caught: groovy.lang.MissingPropertyException: No such property: a for class: ClosureTest at ClosureTest$_run_closure1.doCall(ClosureTest.groovy:2) at ClosureTest$_run_closure1.doCall(ClosureTest.groovy) at ClosureTest.run(ClosureTest.groovy:7) at ClosureTest.main(ClosureTest.groovy)
This happens because when the closure is created it closes over the scope, as it existed at the time, and a hadn't been defined yet.
How do we exploit the fact that closures represent small chunks of functionality that we want to pass around when they close over the scope as it exists when they are created? Groovy provides a mechanism of binding properties to the closure so the closure can reference properties that did not exist when it was created.
Here's our example using a Binding that allows our closure to access a.
def c = {
println a;
}
def a = "Hello"
def binding = new Binding ()
binding.setVariable ("a", a)
c.setBinding (binding)
c.call()
Now our example succeeds.
As previously explained a closure closes over the scope that existed when the closure is instantiated. Using this knowledge take a look at the following example:
def outerClosure = {
def someString = "Some String"
return { println someString }
}
def innerClosure = outerClosure.call()
innerClosure.call()
In this example the variable someString is defined in the scope of outerClosure, then outerClosure returns an anonymous closure. At this point someString is no longer accessible from any scope, at least in the traditional sense, but the scope still exists closed over by the anonymous closure that was returned. The example then assigns the return value of outerClosure to a variable, outerClosure, and then calls it, returning the value of someString.
What do you do with all of this closure and binding goodness? A good example of using the binding can be found in the Grails plugin system. Base functionality of the framework is implemented using this, such as the wiring of service beans by convention.
Another use case off the top of my head, which began leading me down this path, was defining business rules in closures stored in a database. Using bindings, a well defined runtime environment for these closures could be defined, bound in a Binding, and then the closures executed to get the result.
For examples that use the technique from the final example take a look at: Ruby Metaprogramming: Declaratively Adding Methods to a Class. That one is in Ruby but the principles are the same.
I'm on Groovy 1.0 because I have a project that doesn't run under 1.5 for reasons yet unresolved. I think there is a bug in Binding because I think the following code should fail to run, but it doesn't:
try {
def binding = new Binding ()
def someVariable = "some value"
binding.setVariable ("someVariable", someVariable)
c = { true }
c.setBinding (binding)
}
println someVariable
someVariable should not be defined outside the scope of the try block, but it is. Remove the binding stuff from the try block and it does fail saying someVariable is not defined.
Mark
In the first example that you wrote you are closing over i, which we must remember is a reference. Each time through we are closing over the reference that is i, which is what is referred to in the closure when it's invoked.
Just as an FYI, Ruby's behavior is the same as Groovy's.
I'm still working on the second example.
To get the behavior you're looking for try this:
def myArray = []
0.upto(2) { i ->
myArray.add ( {println "Current i is: ${i}"} )
}
myArray.each { it() }
In this example the output from the closure is the value of i when the closure is created in the iteration because each i is a different reference.
Mark
...of your first example:
myArray = []
i = 0
0.upto(2) do
c = Proc.new do
puts i
end
myArray << c
i = i.next
end
myArray.each do |it|
it.call
end
I'm digging into this and will report back what I find.
Mark
Closures and Bindings in Groovy: Question
Great blog post about closure. But it reminds me that I red stuffs like this in "Groovy in Action". By the way, there is still something I don't get: the following programm
Vector myArray = new Vector()
int i = 0
0.upto(2) {
myArray.add( {println "Current i is:"+i} )
i++
}
for ( clos in myArray )
clos.call()
has the following output:
Current i is:3
Current i is:3
Current i is:3
and using the Binding you talk about:
Vector myArray = new Vector()
0.upto(2) {
def clos = {println "Current value is:" + this.it}
def binding = new Binding ()
binding.setVariable ("it", it)
clos.setBinding (binding)
myArray.add( clos )
}
for ( clos in myArray )
clos.call()
has the result:
Current value is:2
Current value is:2
Current value is:2
I don't get how to associate data to a closure...