Tyrion Lannister
Tyrion Lannister

Reputation: 221

scala Closure Free variable

val m1 = 99

val g = (_:Int) + m1

g(10)  // returns 109

val m1 = 88

g(10)  // returns 109

var n1 = 99

val h = (_:Int) + n1

h(10)  // returns 109

n1 = 88

h(10)  // returns  98

var n1 = 66

h(10)  // returns 98

Can someone explain to me how this works? Why is closure not tracking the changes in "free variable"?

The line below is written in Programming in Scala,but i am finding it difficult to link it to above scenario :

Scala’s closures capture variables themselves, not the value to which variables refer.

Upvotes: 2

Views: 788

Answers (4)

LRLucena
LRLucena

Reputation: 1705

What you are doing in the REPL is similar to

object Test extends App{
  val m1 = 99

  val g = (_: Int) + m1

  println(g(10))   // returns 109

  {
    val m1 = 88    // creates a new variable that shadows m1
    println(g(10)) // returns 109
  }
}

You have two variables named m1. The definition of g uses only the first one.

Upvotes: 1

chris
chris

Reputation: 1817

That's because you are using the Repl, which encloses your statements into individual objects and then imports them on subsequent usage. Hence the peculiar behaviour you are witnessing.

See post https://stackoverflow.com/a/22773553/2509908

Upvotes: 0

dk14
dk14

Reputation: 22374

I assume you're trying to do it inside REPL. The explanation is simple when you do either val m1 = or var n1 = second time - you're just making a new definition (you may think of it as m1_2/n1_2), which is not related (in any way) to your previously defined m1/n1. Your h and g are closed to this previously defined values/variables, regardless that they shadowed by new.

P.S. You can't do this trick outside of REPL (on class definition for example)

Upvotes: 2

sjrd
sjrd

Reputation: 22085

This looks like a REPL session. Every time you introduce val m1 or var n1, you shadow the previous definition of a variable with the same name. The shadowing applies to new lines sent to the REPL after that. But lines already compiled still refer to the old variable.

It is easy to explain the above behavior by renaming variables so that no shadowing occurs: introduce new names every time you redeclare something. This yields:

val m1 = 99

val g = (_:Int) + m1

g(10)  // returns 109

val m2 = 88

g(10)  // returns 109

-

var n1 = 99

val h = (_:Int) + n1

h(10)  // returns 109

n1 = 88

h(10)  // returns  98

var n2 = 66

h(10)  // returns 98

In both cases, the definitions of g and h still refer to m1/n1 respectively. The definition of new vals and vars is irrelevant.

However, the assignment n1 = 88 does not introduce a new variable. It changes the value of the existing variable n1. In that case, h sees the updated value of n1.

Upvotes: 6

Related Questions