-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mutable variables maintain state across calls #157
Comments
I'm pretty sure that I can create the same local observable phenomenon with async and ThreadStatic :) |
The behaviour you're seeing is related to two parameters:
Fsi encodes all of its top-level value bindings as static fields. As such, they introduce what I call "implicit data dependencies" to cloud workflows that reference them, since they are not captured by their object graphs. So Vagabond includes functionality that manually replicates such dependencies (and any client-side mutations) across the cluster. If this didn't get done, the initial observed value on the remote process would always be uninitialized, i.e. 0 or So what you're seeing is not entirely unexpected if you rephrase it in the following terms: open System
let workflow = cloud {
let! worker = Cloud.CurrentWorker
let cwd = Environment.CurrentDirectory
Environment.CurrentDirectory <- @"C:\"
return worker.Id, cwd }
for _ in 1 .. 10 do
workflow |> cluster.Run |> printfn "%A" It's essentially just modifying global state in the context of the specific worker. Like @palladin said, same as mutating ThreadStatic fields in multi-threaded applications. |
Btw, representing repl values using static fields is not a necessity. The Roslyn C# repl generates code which uses session objects, effectively eliminating this weirdness you're seeing. We should consider doing the same with fsi codegen. |
Yeah. You can also "fix" this behaviour simply by putting it in a |
@eiriktsarpalis Re Fsi codegen - right, but as I understood from our discussions that comes at the cost of not allowing class-based members to access defined values. So in C# REPL scripting the equivalent of
is not allowed? (since in C# the "let" become instance declarations in an implied class, and the instance would need to be implicitly passed to M(), which is not done) So can we really adjust F# codegen to avoid statics? |
@dsyme Correct, class definitions in C# interactive cannot contain references to repl values at all. In F# the issue could be somewhat addressed by recovering the session object from a static location in such cases only. |
I had a brief chat about this with @eiriktsarpalis but it's worth discussing here in more detail. Look at the following code sample: -
Running the above code produces something like the following: -
I would have expected the values to all be 6, whereas clearly the lifetime of a captured mutable variable is longer living. How does this behave?
What's even stranger is that if I then do
and rerun the workflow another ten times, I get the following output: -
Note that I haven't regenerated the workflow - I simple ran the loop again. So a mutable variable has some state of its own on each node, unless it's modified locally, in which case it gets reset.
By the way I'm not suggesting that this is a good pattern to adopt :-) But I didn't expect this behaviour at all.
The text was updated successfully, but these errors were encountered: