As discussed in Eric Lippert's blog post Closing over the loop variable considered harmful, closing over the loop variable in C# can have unexpected consequences. I was trying to understand if the same "gotcha" applied to Scala.
First of all, since this is a Scala question, I'll try explaining Eric Lippert's C# example adding a few comments to his code
// Create a list of integers
var values = new List<int>() { 100, 110, 120 };
// Create a mutable, empty list of functions that take no input and return an int
var funcs = new List<Func<int>>();
// For each integer in the list of integers we're trying
// to add a function to the list of functions
// that takes no input and returns that integer
// (actually that's not what we're doing and there's the gotcha).
foreach(var v in values)
funcs.Add( ()=>v );
// Apply the functions in the list and print the returned integers.
foreach(var f in funcs)
Console.WriteLine(f());
Most people expect this program to print 100, 110, 120. It actually prints 120, 120, 120.
The issue is that the () => v
function we add to the funcs
list closes over the v variable, not v's value. As v changes value, in the first loop, all the three closures we add to the funcs
list "see" the same variable v, which (by the time we apply them in the second loop) has value 120 for all of them.
I've tried to translate the example code to Scala:
import collection.mutable.Buffer
val values = List(100, 110, 120)
val funcs = Buffer[() => Int]()
for(v <- values) funcs += (() => v)
funcs foreach ( f => println(f()) )
// prints 100 110 120
// so Scala can close on the loop variable with no issue, or can it?
Does Scala indeed not suffer from the same issue or have I just translated Eric Lippert's code badly and have failed to reproduce it?
This behavior has tripped many a valiant C# developer, so I wanted to make sure there are no strange similar gotchas with Scala. But also, once you understand why C# behaves the way it does, the output of Eric Lippert's example code kind of makes sense (it's the way closures work, basically): so what is Scala doing differently?