struct DemoChoreography;
impl Choreography for HelloWorldChoreography {
fn run(self, op: &impl ChoreoOp) {
let mut b = false;
op.locally(Alice, |_| {
b = true;
});
let v_at_bob = op.locally(Bob, |_| 1);
if b {
op.comm(Bob, Alice, &v_at_bob);
}
}
}
This was valid until ChoRus v0.1.2, but this simple program led to a deadlock. Here, we have a mutable variable b that is initially set to false. Alice changes this value to true and takes the then branch on the if statement, while the value remains false on Bob, and it doesn’t go into the then branch. Because Alice expects Bob to send data, but Bob never sends the value, this will lead to a deadlock.
The problem is that local computations (second argument of locally) was FnOnce which can move ownership. We don't want local computation to mutate non-located values because those values can be used for branching and can lead to different execution paths. Changing the FnMut does not solve the problem because it can still have mutable references.
The only option is to require local computation closures to implement Fn. With this change, the local computation can only access outside variables (including located values) through immutable references. Now, the code above does not compile because the closure cannot mutate outside variables.
For convenience, this PR changes the interface of unwrap to take a reference to a located value and returns the reference to the wrapped value. This should not affect how users write choreographies because located values should be immutable.
As illustrated in the tic-tac-toe example, broadcast still takes ownership of located values and returns the unwrapped value with its ownership. This can be used to implement branching.
Consider the following choreography:
This was valid until ChoRus v0.1.2, but this simple program led to a deadlock. Here, we have a mutable variable
b
that is initially set tofalse
. Alice changes this value totrue
and takes thethen
branch on the if statement, while the value remainsfalse
on Bob, and it doesn’t go into thethen
branch. Because Alice expects Bob to send data, but Bob never sends the value, this will lead to a deadlock.The problem is that local computations (second argument of
locally
) wasFnOnce
which can move ownership. We don't want local computation to mutate non-located values because those values can be used for branching and can lead to different execution paths. Changing theFnMut
does not solve the problem because it can still have mutable references.The only option is to require local computation closures to implement
Fn
. With this change, the local computation can only access outside variables (including located values) through immutable references. Now, the code above does not compile because the closure cannot mutate outside variables.For convenience, this PR changes the interface of
unwrap
to take a reference to a located value and returns the reference to the wrapped value. This should not affect how users write choreographies because located values should be immutable.As illustrated in the tic-tac-toe example,
broadcast
still takes ownership of located values and returns the unwrapped value with its ownership. This can be used to implement branching.