So far, you have seen how to declare a closure for the purpose of passing it for execution, to the each method for example. But what happens inside the each method? How does it call your closure? If you knew this, you could come up with equally smart implementations. We’ll first look at how simple calling a closure is and then move on to explore some advanced methods that the Closure type has to offer.
Calling a closure:
Suppose we have a reference x pointing to a closure; we can call it with x.call() or simply x() . You have probably guessed that any arguments to the closure call go between the parentheses. We start with a simple example. Listing 5.5 shows the same closure being
called both ways.
- Listing 5.5 Calling closures
Now let’s try something more involved. In listing 5.6, we demonstrate calling a closure from within a method body and how the closure gets passed into that method in the first place. The example measures the execution time of the closure.
- Listing 5.6 Calling closures
Figure 5.2 shows the UML sequence diagram for the general calling scheme of the declaring object that creates the closure, the method invocation on the caller, and the caller’s callback to the given closure.
When calling a closure, you need to pass exactly as many arguments to the closure as it expects to receive, unless the closure defines default values for its parameters. This default value is used when you omit the corresponding argument. The following is a variant of the addition closure as used in listing 5.5, with a default value for the second parameter and two calls—one that passes two arguments, and one that relies on the default:
More closure methods:
The class groovy.lang.Closure is an ordinary class, albeit one with extraordinary power and extra language support. It has various methods available beyond call . We will present the most the important ones—even though you will usually just declare and call closures, it’s nice to know there’s some extra power available when you need it.
Reacting on the parameter count
A simple example of how useful it is to react on the parameter count of a closure is map ’s each method, which we discussed in section 4.3.2. It passes either a Map.Entryobject or key and value separately into the given closure, depending on whether the closure takes one or two arguments. You can retrieve the information about expected parameter count (and types, if declared) by calling closure’s getParameterTypes method:
How to curry favor with a closure
Currying is a technique invented by Moses Schönfinkel and Gottlob Frege, and named after the logician Haskell Brooks Curry (1900..1982), a pioneer in functional programming. (Unsurprisingly, the functional language Haskell is also named after Curry.) The basic idea is to take a function with multiple parameters and transform it into a function with fewer parameters by fixing some of the values. A classic example is to choose some arbitrary value n and transform a function that sums two parameters into a function that takes a single parameter and adds n to it.
In Groovy, Closure ’s curry method returns a clone of the current closure, having bound one or more parameters to a given value. Parameters are bound to curry ’s arguments from left to right. Listing 5.7 gives an implementation.
- Listing 5.7 A simple currying example
The real power of currying comes when the closure’s parameters are themselves closures. This is a common construction in functional programming, but it does take a little getting used to. For an example, suppose you are implementing a logging facility. It should support filtering of log lines, formatting them, and appending them to an output device. Each activity should be configurable. The idea is to provide a single closure for a customized version of each activity, while still allowing you to implement the overall pattern of when to apply a filter, do the formatting, and finally output the log line in one place. The following shows how currying is used to inject the customized activity into that pattern:
This is the beginning of functional programming. See Andrew Glover’s excellent online article on functional programming with Groovy closures at http://www-128.ibm.com/developerworks/library/j-pg08235/. It expands on how to use this approach for implementing your own expression language, capturing business rules, and checking your code for holding invariants.
Classification via the isCase method
Closures implement the isCase method to make closures work as classifiers in grep and switch . In that case, the respective argument is passed into the closure, and calling the closure needs to evaluate to a Groovy Boolean value (see section 6.1). As you see in
For the sake of completeness, it needs to be said that closures support the clone method in the usual Java sense. The asWriteable method returns a clone of the current closure that has an additional writeTo(Writer) method to write the result of a closure call directly into the given Writer.
Finally, there are a setter and getter for the so-called delegate. We will cross the topic of what a delegate is and how it is used inside a closure when investigating a closure’s scoping rules in the next section.