Summary

During the discussion of the Custom Panic Handler RFC, the idea came up if we could Sync (some) closures. So to start the discussion, I’m writing this Pre-RFC.

Motivation

In multithreaded environments, it may be useful to share callbacks between threads. And callbacks are very commonly defined as closures. The following program tries to share a very simple closure between threads (that don’t even run concurrently):

use std::thread; use std::sync::Arc; fn main() { let x : &'static Fn(u32) = |l| { /* do something with l */ }; let y = &Arc::new(x); // NOPE, this won't compile for v in 1..4 { println!("{:?}", thread::spawn(move|| { y(v); }).join()) } }

This will fail, because the trait core::marker::Sync is not implemented for the type core::ops::Fn(u32) [E0277].

Now, there is nothing within x that would preclude it from being Sync , but rustc doesn’t know that, so it balks.

Detailed Design

The compiler should already know whether a closure is immutable (because of the Fn declaration), and since it already keeps track of captured variables (so it can size the closure-struct), it should be simple enough to determine if a closure is eligible for Sync during compilation.

On detecting such closures, the compiler would then implicitly add a Sync trait bound. The error message for missing Sync on closures should be extended to suggest making the closure an Fn and/or show the captured state.

Drawbacks

It may not be obvious from the code if a closure captures any state. A good error message should remediate this.

It will make the compiler slower, because it has to do the aforementioned additional check for each closure definition.

Alternatives

Leave things as they are

Require the user to state their intention by adding Sync as a trait bound manually when defining the closure. This would reduce the burden on the compiler (since the check would only run if a closure is marked as Sync

Unresolved questions

All of them. This is a Pre-RFC, remember?