Vita Rara: A Life Uncommon

Closures and Bindings in Groovy


Categories: |

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.

Closures

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.

Bindings

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.

More Fun With Closures

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.

Closure and Binding Use Cases

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.

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...

I think there's a bug...

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

Partial answer

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

Here's the Ruby Version...

...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 don't know...

I'm digging into this and will report back what I find.

Mark