Reputation: 221
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
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
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
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
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 val
s and var
s 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