- 12.1 Functions as Values
- 12.2 Anonymous Functions
- 12.3 Parameters That Are Functions
- 12.4 Parameter Inference
- 12.5 Useful Higher-Order Functions
- 12.6 Closures
- 12.7 Interoperability with Lambda Expressions
- 12.8 Currying
- 12.9 Methods for Composing, Currying, and Tupling
- 12.10 Control Abstractions
- 12.11 Nonlocal Returns
- Exercises
12.6 Closures
In Scala, you can define a function inside any scope: in a package, in a class, or even inside another function or method. In the body of a function, you can access any variables from an enclosing scope. That may not sound so remarkable, but note that your function may be called when the variable is no longer in scope.
Here is an example: the mulBy function from Section 12.3, “Parameters That Are Functions,” on page 171.
def mulBy(factor : Double) = (x : Double) => factor * x
Consider these calls:
val triple = mulBy(3) val half = mulBy(0.5) println(s"${triple(14)} ${half(14)}") // Prints 42.0 7.0
Let’s look at them in slow motion.
The first call to mulBy sets the parameter variable factor to 3. That variable is referenced in the body of the function (x : Double) => factor * x, which is stored in triple. Then the parameter variable factor is popped off the runtime stack.
Next, mulBy is called again, now with factor set to 0.5. That variable is referenced in the body of the function (x : Double) => factor * x, which is stored in half.
Each of the returned functions has its own setting for factor.
Such a function is called a closure. A closure consists of code together with the definitions of any nonlocal variables that the code uses.
These functions are actually implemented as objects of a class, with an instance variable factor and an apply method that contains the body of the function.
It doesn’t really matter how a closure is implemented. It is the job of the Scala compiler to ensure that your functions can access nonlocal variables.