Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why 'for .. in' allowed in closures?

Mutable values are not allowed in closures, but the for .. in expression is ok. In C# the for loop updates the iterator, but not in F# as it seems. How and why?

like image 997
aikixd Avatar asked Dec 07 '22 21:12

aikixd


1 Answers

F#'s for .. in is equivalent to C#'s foreach loop, not C#'s for loop. And since C# 5, the foreach loop does not update the iterator; it instead creates a new variable for each iteration through the loop (this has important implications for closures; see Foreach now captures variables! (Access to modified closure) for details. This is also what F# does: if you write

for txt in ["abc"; "def"; "ghi"] do
    printfn "%s" txt

then you're actually creating three new string variables when you run that loop, not just one.

To prove to yourself that F# is creating a new variable each time, try the following not-very-functional code:

let actions = new System.Collections.Generic.List<System.Action<unit>>()
for txt in ["abc"; "def"; "ghi"] do
    actions.Add(fun () -> printf "%s " txt)
for action in actions do
    action.Invoke()

If txt was the same variable each time through the for .. in loop, this would print ghi ghi ghi, just like C# 4 and earlier would have -- because the anonymous function closed over the variable, and after the loop the variable contains ghi. But if you run the above code, you'll see that it prints abc def ghi, like C# 5 and later do.

So the answer to your question is that F# allows for .. in in a closure because it's not actually mutating anything.

like image 68
rmunn Avatar answered Dec 16 '22 19:12

rmunn