1

When you think you know, you don't know, is what went through my head earlier today. While going over someone's code I noticed something similar to:

task {
    let mutable pleaseContinue = true
    let mutable state = MyState.Running
    while pleaseContine do
        match x with
        | Ok -> 
             // do something
             do! runSomeTasks()
             state <- MyState.Running
             pleaseContinue <- true
        | Error err ->
             do! Log.Fatal err "Something bad"
             state <- MyState.Crashed
             pleaseContinue <- false
        | ... // originally many other states
    return 
}

Basically, whenever I see mutable in someone else's code I tend to want to get rid of it. But short of that, I found myself wondering whether the mutable variables inside task and the like are properly part of the closure and are safe to read/update/write, as long as they aren't defined outside the task CE builder.

Is this a correct and safe assumption?

This is in F# 6.0, and using Microsoft.FSharp.Control.TaskBuilder and friends.

Abel
  • 56,041
  • 24
  • 146
  • 247

1 Answers1

2

This looks fine to me.

See https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions.

The builder implements the body of the while loop as a recursive function. It can modify state and pleaseContinue since the variables are in scope.

I'm just not clear where the x that you refer to is declared or mutated - presumably as part of the omitted code before the return statement. In any case, if it is in scope, it should be fine.

Roland Andrag
  • 437
  • 4
  • 9
  • Thanks. This confirms what I thought, but I needed confirmation. I left `x` out (and 200 other lines of code), but it wasn't an external mutable var, just an normal immutable let-binding. – Abel May 06 '22 at 09:47
  • Hmm, come to think of it: `while` becomes a `rec` function, but the vars are declared outside of it. If it is a `rec` function, it can only be run by one thread. But if it isn't and the `while` is parallelized (it's a task CE), that sounds like a potential problem still... Any thoughts? – Abel May 06 '22 at 09:50