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.

Reply

Please solve the math problem above and type in the result. e.g. for 1+1, type 2
  • Allowed HTML tags: <a> <img> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <pre> <h1> <h2> <h3>
  • Lines and paragraphs break automatically.
More information about formatting options