Therii
Therii

Reputation: 838

Use of closure in scala

I'm new to scala. I was reading about closure than I came across the definition of closure saying that:

"The name arises from the act of "closing" the function literal by "capturing" the bindings of its free variables" .

What does this line actually mean? How is closure really helpful? And what are is it's use-cases?

Upvotes: 2

Views: 1675

Answers (2)

Andrey Tyukin
Andrey Tyukin

Reputation: 44918

What are free variables?

Consider the function literal for curried multiplication:

(x: Int) => (y: Int) => x * y

If you consider only the subexpression e := (y: Int) => x * y, then you can compute the set of free variables in e recursively as follows (starting from leafs x and y, and then building up the expression from its parts):

  • FREE(x) = {x} because x is a variable
  • FREE(y) = {y} because y is a variable
  • FREE(*) = {} because * is a built-in constant, for all practical purposes
  • FREE(x * y) = FREE(*) U FREE(x) U FREE(y) = {} U {x} U {y} = {x, y} by recursive descent into subtrees
  • FREE( (y: Int) => x * y ) = FREE(x * y) - {y} = {x, y} - {y} = {x}, because the variable y is bound by the in-line function definition, and therefore the variable y from FREE(x * y) becomes no longer free.

Thus the variable y is bound and x is free in the expression (y: Int) => x * y.


What are closures?

Now, what happens if you take the whole expression (x: Int) => (y: Int) => x * y and apply it to some constant, 7, say? What is returned?

The returned object is a closure of the expression (y: Int) => x * y, where the free variable x is set to value 7. So, in a sense, the result of

((x: Int) => (y: Int) => x * y)(7)

is something like an object with a single method, that looks roughly like

class y_to_x_times_y_closure(x: Int) {
  def apply(y: Int) = x * y
}

instantiated as y_to_x_times_y_closure(7). Note that the value 7 cannot reside in the call stack of some function, because you can easily produce a whole bunch of closures like

for (i <- 0 to 1000) yield ((x: Int) => (y: Int) => x * y)(i))

that will have to coexist simultaneously in the same thread, with different captured values of i bound to the variable x. Therefore, the closures in Scala are implemented as heap-resident objects.


Why is this useful?

This is actually a way too broad question: it enables you to do functional programming. It's built into the language at such a deep level, that you can't really do anything without using tons of closures everywhere.

Consider the following trivial example: printing the multiplication table of one-digit numbers:

for (x <- 1 to 9) {
  for (y <- 1 to 9) {
    printf("%3d", x * y)
  }
  println()
}

This produces:

  1  2  3  4  5  6  7  8  9
  2  4  6  8 10 12 14 16 18
  3  6  9 12 15 18 21 24 27
  4  8 12 16 20 24 28 32 36
  5 10 15 20 25 30 35 40 45
  6 12 18 24 30 36 42 48 54
  7 14 21 28 35 42 49 56 63
  8 16 24 32 40 48 56 64 72
  9 18 27 36 45 54 63 72 81

Those for-loops are actually desugared into the following method applications on the Range objects 1 to 9:

 (1 to 9) foreach { x => 
   (1 to 9) foreach { y =>
     printf("%3d", x * y)
   }
   println()
 }

What's the y => printf("%3d", x * y)-thing that is passed to the inner foreach? It is actually an expression with the free variable x. In order to print anything meaningful, it has to capture the value of x, which is in turn set to values 1 to 9 by the outer foreach. Thus, the inner foreach works with a closure of y => printf("%3d", x * y), where x is set to values 1 to 9.

Upvotes: 7

nicodp
nicodp

Reputation: 2392

This is an open term:

def sumMore(x: Int): Int = x + more

as more appears as a free variable, i.e., its value does not have a binding inside sumMore's body. Hence, you get:

scala> def sumMore(x: Int): Int = x + more
<console>:7: error: not found: value more
       def sumMore(x: Int): Int = x + more
                                      ^

You make this open term a closed one, i.e., the act of closing, by providing a binding for more.

So instead if you have

val more: Int = 5
def sumMore(x: Int): Int = x + more

you'll have a closure as you are closing sumMore by providing a value for more.

You can see this pattern in nested functions:

def fib(n: Int): Int = {
  var num: Int = n
  def innerFib(prev: Int, actual: Int): (Int, Int) = {
    if (num == 0) (prev, prev)
    else if (num == 1) (prev, actual)
    else {
      num -= 1
      innerFib(actual, prev + actual)
    }
  }
  innerFib(0, 1)._2
}

Here, innerFib along with the variable num are a closure, as in the scope of fib's body, num is providing a binding for the free variable num that appears inside innerFib's body.

Upvotes: 3

Related Questions