Closures

In the examples you’ve seen so far in this chapter, the variables and values used in the function values or code blocks were bound. You clearly knew what they were bound to, local variables or parameters. In addition, you can create code blocks with variables that are not bound. You’ll have to bind them before you can invoke the function; however, they could bind to, or close over, variables outside of their local scope and parameter list. That’s why they’re called closures.

Let’s look at a variation of the totalResultOverRange method you saw earlier in this chapter. The method loopThrough in this example iterates over the elements from 1 to a given number:

FunctionValuesAndClosures/Closure.scala
 
def​ loopThrough(number: ​Int​)(closure: ​Int​ => ​Unit​) {
 
for​ (i <- 1 to number) { closure(i) }
 
}

The loopThrough method takes a code block as the second parameter, and for each element in the range of 1 through its first parameter, it calls the given code block. Let’s define a code block to pass to this method:

FunctionValuesAndClosures/Closure.scala
 
var​ result = 0
 
val​ addIt = { value:​Int​ => result += value }

Here, we have defined a code block and assigned it to the variable named addIt. Within the code block, the variable value is bound to the parameter. However, the variable result is not defined within the block or its parameter list. This is actually bound to the variable result outside the code block. The code block stretches its hands and binds to a variable outside. Here’s how we can use the code block in calls to the method loopThrough:

FunctionValuesAndClosures/Closure.scala
 
loopThrough(10) { elem => addIt(elem) }
 
println(s​"Total of values from 1 to 10 is $result"​)
 
 
result = 0
 
loopThrough(5) { addIt }
 
println(s​"Total of values from 1 to 5 is $result"​)

When we pass the closure to the method loopThrough, the parameter value is bound to the parameter passed by loopThrough, while result is bound to the variable in the context of the caller of loopThrough.

The binding did not get a copy of the variable’s current value; it’s actually bound to the variable itself. When we reset the value of result to 0, the closure sees this change as well. Furthermore, when the closure sets result, we see it in the main code. Here’s another example of a closure bound to yet another variable product:

FunctionValuesAndClosures/Closure.scala
 
var​ product = 1
 
loopThrough(5) { product *= _ }
 
println(s​"Product of values from 1 to 5 is $product"​)

In this case, the _ refers to the parameter passed in by loopThrough, and product is bound to the variable with that name in the caller of loopThrough. Here’s the output from the three calls to loopThrough:

 
Total of values from 1 to 10 is 55
 
Total of values from 1 to 5 is 15
 
Product of values from 1 to 5 is 120

You’ve come a long way in this chapter; you learned about function values and how to use them. Let’s now put function values to a practical use with the help of a design pattern.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.184.0