CHAPTER 9
A closure is a function that computes with variables defined outside the body of the function. Code Listing 91 shows a simple example of a closure. Closures are sometimes called Lambda functions, and they are similar to Java’s anonymous functions. Closures are one of the many mechanisms offered by Scala from the functional programming paradigm (as opposed to the object-oriented programming paradigm).
Code Listing 91: Simple Closure
object MainObject { def main(args: Array[String]) = {
// Define a variable: var divisor = 9
// Define a closure which uses the divisor // variable: var divideClosure = (i: Int) => i / divisor
// Execute the closure using 90 as the // Int i: println("90/9=" + divideClosure(90)) } } |
In Code Listing 91, we define a closure called divideClosure. First, we specify an identifier for the closure, divideClosure, then we use the equals operator to set it to a parameter list = (i: Int). We then use the => operator (sometimes called rocket) and specify the body of the closure. Notice that the closure uses the variable called divisor, which is defined outside the body of the closure. In this particular instance, the variable divisor is still in scope, but as we will see, this does not need to be the case.
Also note that the use of variable divisor in the body of the closure does not shadow the local variable divisor as we might expect, especially considering some of the previous examples we have examined. The divisor variable in the closure is the local variable divisor.
We should note that closures do not need to use external variables. We can define a closure that uses only the parameters defined in its own parameter list. Also, the closure evaluates the values of the variables, so that when we update the values of the variables defined outside the body of the closure, the return value of the closure will be updated, too.
Code Listing 91 provided a completely redundant example of a closure, but that is actually an interesting mechanism. Another interesting aspect of closures is that we can pass them as parameters to a method. Code Listing 92 shows an example of this. It might not seem strange yet, but it will when we look at its implications.
Code Listing 92: Passing a Closure as a Parameter
object MainObject { def executeClosure(closure: (Int) => Int, parameter: Int) { println("The closure said: " + closure(parameter)) }
def main(args: Array[String]) = { var divisor = 9 var divideClosure = (i: Int) => i / divisor
executeClosure(divideClosure, 125) } } |
In Code Listing 92, we define a function called executeClosure. The function takes two parameters—one is a function called closure and the other is a parameter. The executeClosure function executes the function and prints the result to the screen. The function is a roundabout way of dividing 125 by nine, and it prints 13 to the screen, which is perhaps not very interesting (this is just basic integer arithmetic, 125/9=13.888, and the 0.8888 is truncated as per the normal rules of integer arithmetic). However, let’s have a quick look at another example. This time, let’s illustrate something slightly strange about the way closures work.
Code Listing 93: Altering a Closure’s Variable
object MainObject { def executeClosure(closure: (Int) => Int, parameter: Int) { println("The closure said: " + closure(parameter)) }
def main(args: Array[String]) = { var divisor = 9 var divideClosure = (i: Int) => i / divisor
divisor = 45 executeClosure(divideClosure, 125) } } |
In the main method of Code Listing 93, we define the same closure as before. This time, however, I have added a line and reassigned the divisor variable, setting it to 45. When we call the function executeClosure and pass the parameter 125, the closure will execute 125/45 even though the divisor variable is out of scope at the point of execution and it has been changed since the closure was defined. Code Listing 93 correctly computes the result that 125/45 is 2.
A closure, therefore, is a function we can pass around and that is able to refer to variables that are not in scope.
There is a shorthand syntax for simple closures. We can use the _ (the underscore wild card symbol) to mean a single parameter, if there is one. So if the closure takes only a single parameter, we can use the _ instead of a formal parameter list. See Code Listing 94 for an example of this.
Code Listing 94: Shorthand for Closure
object MainObject { def main(args: Array[String]) = {
// Define divisor variable. var divisor = 9
// Define a closure using _ syntax: var divideClosure = (_:Int) / divisor
// Again, this closure will divide 125 by 9 // and return 13: println("125/9=" + divideClosure(125)) } } |
Notice that in Code Listing 94 we need to specify the data type of the _ symbol with (_: Int). If the data type is specified in the closure already, we can use the underscore by itself.
Code Listing 95 shows a slightly more complicated example of a closure. This particular use of a closure is commonly used for performing operations on lists and arrays.
Code Listing 95: Passing Functionality as a Parameter
object MainObject { def main(args: Array[String]) = {
// Define a functions which takes two ints, x and y // and a function to perform between them called func: def performOperation (x: Int, y: Int, func: (Int, Int)=>Int): Int = func(x, y)
// Call the perform operation function with 78 and 26 // as the Int parameters, and with the closure (a, b)=> // a-b as the func parameter: println("78-26=" + performOperation(78, 26, (a, b)=>a-b))
// Call the perform operation function with 6 and 5 // as the Int parameters, and with _+_ short hand // closure as the func parameter: println("6+5=" + performOperation(6, 5, _+_)) } } |
In Code Listing 95, we define a function called performOperation. The function takes three parameters—two Int and a function. The function parameter is called func. It takes two inputs of its own and returns an Int (this is all specified by the (Int, Int)=>Int). The performOperation function performs whichever operation we pass as a final argument between the two Int parameters and returns the result.
Tip: Notice the use of the wild card symbol in the second call to the closure in Code Listing 95. When we use multiple wild cards, such as _+_, the first is assigned to the first parameter and the second to the second parameter, etc. The _+_ is shorthand for a+b since a is the first parameter and is substituted for the first occurrence of _. And b is the second parameter—it is therefore substituted with the second instance of _.
The most important aspect of Code Listing 95 is how we call the function. Notice that with the first call to performOperation, we pass 78, 26 as the integer parameters, then we specify the functionality of the func closure using (a, b)=>a-b. This means we want the second parameter to be subtracted from the first, so that the first println will output 78-26=52. The second call uses the wild card symbol and the shorthand syntax for the functionality.