VII Closures

64. Introduction

Closures represent a reference to a function (method) that is accompanied by a referencing environment. This means that you can store function references in a variable and pass them to a function and that the original scope of the closure is available. Confused? Well, let’s get into it!

65. Introducing Closures

In the last tutorial we looked at methods and this prepares us as we start to look at closures. If you take a look at the following code you’re likely to quickly see what the printer() method does:

Using a method reference
def printer() {
    println 'Hello, world'
}

def cls = this.&printer
cls()

So what about def cls = this.&printer? Well, .& is the Method Reference operator and it returns a reference to the printer() method. I use this in the script as I need to reference the current instance in which I’m running - remember that Groovy wraps the script in a class.

Once I have the reference I can then call the closure with cls().

Note the following:

  1. When I define the closure (def cls = this.&printer) I don’t put the parentheses after the method name (printer)
  2. When I call the closure I pass in the parameters

Say I set this up a little differently and create a Test class with two printer methods - one that takes a parameter and one that doesn’t:

Overloading and method references
class Test {
    static printer() {
        println 'Hello, world'
    }

    static printer(name) {
        println "Hello, $name"
    }
}

def cls = Test.&printer
cls()
cls('Newman')

You’ll see if you run that last example that the call to the closure (cls) will result in the associated method being called depending on the parameters I provide.

Anonymous Functions

In the first examples of this chapter I used the Method Reference operator to point to an existing method that I had defined in a class. Closures can also be defined using anonymous functions. This lets us create a function at the point we define the variable.

In the next example I create an anonymous function using the regular block syntax ({..}) and store the function reference in cls:

A basic closure
def cls = { println 'Hello, world' }
cls()

That’s pretty nifty! We can define a function when needed and store it in a variable. This variable can then be passed to methods and other closures as a parameter.

The ‘it’ parameter

Anonymous functions get a single parameter named it by default. That means that you can use it as a parameter inside your function and it will contain the parameter passed in the call to the closure.

Let’s write a version of the printer method that uses the it parameter:

Using it
def cls = { println "Hello, $it" }
cls('Jerry')

66. Parameters

We just saw that closures have an in-built it parameter but we can specify a parameter when we declare the closure:

Specifying a parameter
def cls = { name -> println "Hello, $name" }
cls('Jerry')

In the example above I declare the name parameter and this replaces it - in fact, if I called it within the closure I’d get an exception.

The syntax of closures is starting to become evident:

  1. Start the closure with {
  2. List parameters, followed by ->
  3. Write a set of statements for the closure body
  4. End the closure with }

Each parameter is separated using a comma (,):

Specifying two parameters
def cls = { name, pet -> println "Hello, $name. How is your $pet?" }
cls('Jerry', 'cat')

As the closure gets more complicated I like to break it up over a number of lines. I start the closure and declare the parameters on the first line. The body of the closure then follows much the same as a method body and a final line closes off the closure:

Formatting a closure
def cls = { name, pet ->
    println "Hello, $name. How is your $pet?"
}

cls('Barry', 'Lemur')

Closure parameters let me do the same things I can do with method parameters:

  1. Use data types for parameters
  2. Provide default values
  3. Varargs
  4. Named parameters

Parameter data types:

Specifying typed parameters
def cls = { String name, String pet ->
    println "Hello, $name. How is your $pet?"
}

cls('Sally', 'Echidna')

Default values:

Specifying parameters with default types
def cls = { name, pet = 'dog' ->
    println "Hello, $name. How is your $pet?"
}

cls('Barry')

Varargs:

Specifying varargs
def cls = { name, ... pets ->
    println "Hello, $name. How are your $pets?"
}

cls('Herman', 'cat', 'dog', 'spider')

Named parameters:

Specifying “named” parameters
def cls = { grades, name ->
    println "This year $name received the following grades: $grades"
}

cls(maths: 'D', science: 'C', art: 'A', 'Albert')

So closures and methods are rather similar - there’s no black magic going on.

67. Returning Values

Just like methods, closures can return a value. In this next example, the result of the last expression is returned (the value of num1 or num2):

Returning a value
def max = { num1, num2 ->
    if (num1 >= num2) {
        num1
    } else if (num2 > num1) {
        num2
    }
}

println max(14, 6)

Alternatively, we can use the return statement to explicitly exit the closure and return a value:

Explicitly returning a value
def myClosure = { num1, num2 ->
    if (num1 >= num2) {
        return num1
    } else if (num2 > num1) {
        return num2
    }
}

println myClosure(14, 6)

Unlike a method, closures can’t explicitly define the data type of a return value. You might take a crack at Integer maxNumber = {num1, num2 -> ...} to set the return type but this statement won’t work as maxNumber doesn’t hold the result of the closure - it holds a reference to the closure.

Closure myClosure = { num1, num2 -> ...} will work as the myClosure variable is actually of the Closure data type.

68. Closures as Method Parameters

We often say closures are first-class citizens in Groovy. This means that you can use them across the language in a similar manner to other first-class citizens, such as variables.

The best example to start our exploration is the each method that’s available to your collections (lists and maps). each can be called on a list or a map and is passed a closure as a parameter, allowing you to perform operations on each member of the collection. In the next example I call each on the numList variable and pass it a very basic closure as a parameter:

def numList = [6, 9, 11, 4, 7]
def myClosure = { println it }
numList.each(myClosure)

However, we can avoid myClosure altogether as we don’t really need to use it anywhere else in our code. So, we use an anonymous closure - one that doesn’t get a name (i.e. assigned to a variable). This is really useful if we don’t need to use the closure outside of the method being called:

def numList = [6, 9, 11, 4, 7]
numList.each({ println it })

Whilst the closure can be placed within the (...) parentheses, this becomes cumbersome for larger anonymous closures so Groovy lets us drop the parentheses:

def numList = [6, 9, 11, 4, 7]
numList.each { println it }

For a final example, we can call the each method directly against the literal array, just to prove that Groovy has a versatile and flexible syntax:

[6, 9, 11, 4, 7].each { println it }

Methods with Closure Parameters

Your own methods can accept one or more closures as a parameter. When doing this we usually follow a basic convention of:

  • Use closure as the parameter name
  • Put the closure parameter at the end of the parameter list

In the example below, the mutator method accepts a closure as the second parameter:

def mutator(value, closure) {
    closure(value)
}

mutator 10, {it**2}

We are able to call mutator in a number of ways:

  • mutator(10, {it**2})
  • mutator 10, {it**2}
  • mutator(10) {it**2}

Those last two options are very useful if you’re going to pass a non-trivial closure as it helps the reader see that the last parameter is a closure and not some random block.

Here’s another example, a method findPrimes that accepts a list of numbers (such as a range) and a closure. The method loops through the list and, when it determines the item is a prime number it will call our closure:

Finding primes
def findPrimes(list, closure) {
    list.each {
        def isPrime = true
        if (it != 2) {
            for (divisor in (2..it / 2)) {
                if (it % divisor == 0) {
                    isPrime = false
                    break
                }
            }
        }
        if (isPrime) {
            closure(it)
        }
    }
}

def numList = (1..100)
findPrimes numList, { println "I found a prime: $it" }

If I wanted to be specific about my parameter data types, the correct data type for closure is Closure. This lets me prepare a static typed method signature of def findPrimes(List list, Closure closure)

One last round at this one - this time to set a return value from the findPrimes method. The code is not really different to the previous example but it throws a number of items together: a typed method signature, a closure parameter, and a return value for the method (the list of primes).

Finding primes, part 2
List findPrimes(List list, Closure closure) {
    def result = [ ]
    list.each {
        def isPrime = true
        if (it != 2) {
            for (divisor in (2..it / 2)) {
                if (it % divisor == 0) {
                    isPrime = false
                    break
                }
            }
        }
        if (isPrime) {
            result << it
            closure(it)
        }
    }
    result
}

def primes = findPrimes 0..100, { println "I found a prime: $it" }

println primes

69. Loops and closures

A number of Groovy types (such as lists and maps) support methods like each which call a closure on each member of a collection. These are similar to loops (for and while) but each call to the closure is discreet and you can’t use the break branching statement to exit as you would with a loop. However, you can use return as somewhat of a proxy for continue.

In this chapter we’ll take a look at a number of these methods.

each

We looked at each in the previous chapter but let’s do one more. In the example below I determine the average of a list of numbers and then use the each method to tell us something about each number’s relationship to the average:

Using each
def scores = [ 2, 4, 6, 8, 10 ]
def total = 0
def average = 0

for (i in scores) {
    total += i
}

average = total / scores.size

println "The average of the scores ($scores) is $average"

scores.each {
    print "The value $it is "

    if (it > average) {
        println 'above average'
    } else if (it < average) {
        println 'below average'
    } else {
        println 'average'
    }
}

collect

The collect method calls a closure for each item in a list and returns a list of the results from each closure call. This next example takes a list of test scores and uses the closure’s algorithm for returning a list of grades:

Using collect
def grades = [ 45, 70, 95, 51 ].collect {
    switch (it) {
        case (90..100):
            'A'
            break
        case (70..89):
            'B'
            break
        case (50..69):
            'C'
            break
        default:
            'F'
    }
}

println grades

sort

The sort method, when called on a list, will use the closure to evaluate a sorting algorithm and alter the list to reflect its sorted form.

In the next example I provide a very basic sorting closure - one that just returns the length of the string it’s passed. This means that the sort method will return a list with the shortest string first:

assert ['cat', 'rabbit', 'ox'].sort{it.length()} == ['ox', 'cat', 'rabbit']

In this use of sort the closure accepts a single parameter and returns a numerical value. sort uses this result to determine the list item’s new place in the sorted list. A string of length 2 will be placed at an earlier index to a string with a length of 6.

It’s important to remember that the list is changed by the sort method - the next example highlights this as the animals variable is different after sort is called.

def animals = ['cat', 'rabbit', 'ox']
animals.sort{it.length()}
assert animals == ['ox', 'cat', 'rabbit']

When the sort method is passed a closure that accepts two parameters then it works through the list by comparing neighbours. As sort changes the list, these neighbours change, resulting in the closure undertaking a number of comparisons, at least equal to the number of list items. This is powerful stuff so let’s look at a sorting closure I used when discussing Relational Operators:

Using sort
def nums = [ 42, -99, 6.3, 1, 612, 1, -128, 28, 0 ]

//Ascending
nums.sort { n1, n2 -> n1 <=> n2 }

assert nums == [ -128, -99, 0, 1, 1, 6.3, 28, 42, 612 ]

70. Useful Methods That Use Closures

Groovy adds a number of methods to java.lang.Object that gives you the power of closures baked into many of the data types you’ll use on a daily basis.

any

The any method is passed a closure that evaluates a criteria (condition). If any element in the collection meets that criteria, true is returned. Importantly, any will only iterate through the list until it the criteria is met.

def scores = [10, 8, 11, 6]
assert scores.any {it > 10} == true

find and findAll

The find method locates the first item in a collection that meets the criteria set in the closure:

def animals = ['dog', 'rat', 'cat', 'mouse']
assert animals.find {it in ['rat', 'mouse', 'wild pig'] } == 'rat'

The findAll method is similar to find but returns all collection items that meet the criteria set by the closure:

def animals = ['dog', 'rat', 'cat', 'mouse']
assert animals.findAll {it in ['rat', 'mouse', 'wild pig'] } == ['rat', 'mouse']

split

The split method splits a collection into two lists: the first list contains all items that meet the criteria set by the closure parameter and the second list contains all remaining items.

In the example below I use the split method to get a list of those who got a score over 100 and those that didn’t.

Using split
def players = [
        [ name: 'Fred', topScore: 120 ],
        [ name: 'Sally', topScore: 200 ],
        [ name: 'Felix', topScore: 101 ],
        [ name: 'Albert', topScore: 12 ],
        [ name: 'Jane', topScore: 20 ]
]

def result = players.split { it.topScore > 100 }

result[0].each { println "$it.name is in the hall of fame" }

result[1].each { println "$it.name missed out" }

with

The with method provides a handy approach to calling several methods and manipulating fields for an object.

In the example below I use with to perform a set of operations on an instance of the Person class:

Using with
class Person {
    def name
    def email
    def mobile

    def printBusinessCard() {
        println "$name"
        println "e: $email"
        println "m: $mobile"
    }
}

def john = new Person()

john.with {
    name = 'John Smith'
    email = 'john@example.com'
    mobile = '0401 999 888'
    printBusinessCard()
}

This approach can be really useful when creating an object. In the snippet below I create a new Person and set up their details at the same time:

Using with at instantiation time
class Person {
    def name
    def email
    def mobile

    def printBusinessCard() {
        println "$name"
        println "e: $email"
        println "m: $mobile"
    }
}

def stacey = new Person().with {
    name = 'Stacey Jane'
    email = 'stacy@example.com'
    mobile = '0401 333 666'
    //This is the same as saying 'return it':
    it
}
stacey.printBusinessCard()

71. Closure scope

In the first chapter on closures I mentioned that: Closures represent a reference to a function (method) that is accompanied by a referencing environment. Up to now we’ve mainly used closures as methods that can be referenced by variables or passed as parameters. Methods declared in classes can access the fields in their class and closures can also access items such as variables available in the context from which they were created.

I’ve tried to demonstrate this concept in the example below. You’ll notice that my basic closure refers to a variable code that isn’t a declared parameter of the closure nor is it a variable declared within the closure. Rather, code references a variable available within the scope in which the closure is declared - i.e. code can be accessed by the doubleCross closure as both are declared in the same block.

A small example of context
def spyMethod(closure) {
    closure()
}

def code = 'eagle'

//This is the closure
def doubleCross = { println "The code is $code" }

spyMethod(doubleCross)

code = 'badger'
spyMethod(doubleCross)

A More Involved Example

My doubleCross was quite basic and perhaps makes the usefulness of this concept appear to be ho-hum. In fact, it’s extremely useful and opens the door to techniques such as Domain Specific Languages - something for you to research later. For now, I’ll take you through a step-by-step example of a more complex use of closure context.

First of all I’ll create a very basic class to describe an address book Contact. For each contact I’ll record their name and phone number. I’ll also define a closure named call and this is a simple function that I can use when calling the contact.

class Contact {
    def name
    def phone

    final call = { message ->
        println "Calling ${this.name} on ${this.phone} with the message: '$messa\
ge'"
    }
}

Once I’ve defined the Contact class I’ll create a couple of contacts - Andrew and Sally.

def andrew = new Contact(name: 'Andrew', phone: '+61 432 321 736')
def sally = new Contact(name: 'Sally', phone: '+61 400 800 900')

I’ll then create a list of Contacts I need to call back (perhaps my mobile phone battery died) and add Andrew and Sally. You’ll note that I don’t add the Contact instances to the call-back list, I actually add the closure for each contact. Think of this as the statement “I’ll add to the list the activity of calling the contact”.

def needToCallBack = []
needToCallBack << andrew.call
needToCallBack << sally.call

Imagine that a whole lot of other code now “does stuff” and eventually we discard the andrew and sally variables:

andrew = null
sally = null

Now this is where it gets interesting. What if my mobile battery is now recharged and I want to start calling people back? Surely the fact that I blew away my andrew and sally variables would make this impossible? Well, remember how my needToCallBack list contains references to the call closures? These closures actually hang on to their original context - the andrew and sally instances.

All of this means that I can now use the each method on needToCallBack and I can realise those closures:

needToCallBack.each { it('It\'s Duncan here, sorry I missed your call') }

This will now cause each of the call closures to be called - allowing me to get back in touch with andrew and sally.

I broke up the code in the discussion so present it all here in full for you copy and try out for yourself:

The complete Groovy message service
class Contact {
    def name
    def phone

    //A closure for calling the contact
    final call = { message ->
        println "Calling ${this.name} on ${this.phone} with the message: '$messa\
ge'"
    }
}

def andrew = new Contact(name: 'Andrew', phone: '+61 432 321 736')
def sally = new Contact(name: 'Sally', phone: '+61 400 800 900')

def needToCallBack = [ ]
needToCallBack << andrew.call
needToCallBack << sally.call

// Lots of other code ......

andrew = null
sally = null

needToCallBack.each { it('It\'s Duncan here, sorry I missed your call') }