# \`dyn FnOnce\` should always be \`Sync\`

**URL:** <https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470>\
**Category:** Unsafe Code Guidelines\
**Created:** [April 14, 2022, 6:52am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470 "2022-04-14T06:52:10Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![kvark](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kvark/32/645_2.png) [@kvark](https://internals.rust-lang.org/u/kvark)\
**Post date:** [April 14, 2022, 6:52am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/1 "2022-04-14T06:52:10Z")

</div>

It appears right now that there are no special rules for `FnOnce` related to `Sync`. This makes things like `Arc<Box<dyn FnOnce() + Send>>` impossible, which is annoying.

I believe `dync FnOnce` is always `Sync` because there are no (unsafe) operations that could be done on `&FnOnce` (from multiple threads). The only operation is consuming `self`, so it's not available behind a reference.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [April 14, 2022, 7:06am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/2 "2022-04-14T07:06:36Z")

</div>

~~There is no need for special rules, can be just a supertrait (in case this is indeed sound - haven't checked it).~~ **Edit:** Oh it will make `Fn` and `FnMut` require `Sync` too.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [April 14, 2022, 7:30am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/3 "2022-04-14T07:30:41Z")

</div>

Why would we want this at all? What does this enable? You cannot do anything with it!

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [April 14, 2022, 7:36am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/4 "2022-04-14T07:36:52Z")

</div>

This is also incompatible with multiple `dyn Trait`s, because this will allow `dyn FnOnce() + Clone` for example.

---

<div class="post-metadata">

**Author:** ![kvark](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kvark/32/645_2.png) [@kvark](https://internals.rust-lang.org/u/kvark)\
**Post date:** [April 14, 2022, 8:06am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/5 "2022-04-14T08:06:23Z")

</div>

Arc is useful because you can share it. Eventually you can extract it via `Arc::into_raw` and execute. See also - [Lift Sync requirement by kvark · Pull Request #3 · kvark/choir · GitHub](https://github.com/kvark/choir/pull/3)

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [April 14, 2022, 8:40am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/6 "2022-04-14T08:40:25Z")

</div>

And how do you call it after? AFAIK we have no way to call `dyn FnOnce` on a raw pointer.

---

<div class="post-metadata">

**Author:** ![kvark](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kvark/32/645_2.png) [@kvark](https://internals.rust-lang.org/u/kvark)\
**Post date:** [April 14, 2022, 8:47am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/7 "2022-04-14T08:47:54Z")

</div>

Sorry for confusion! I meant `Arc::try_unwrap`, which gives you the value back. See [relevant code](https://github.com/kvark/choir/blob/827cb44cafa4e0b81d4b32b97692cba139abdd24/src/lib.rs#L155-L156) for example.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [April 14, 2022, 9:04am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/10 "2022-04-14T09:04:45Z")

</div>

Oh I got it, I think. But it already requires `Send` to be useful, so why not write the `Sync` explicitly too?

You essentially want to work around a limitation of the type system. You don't really share the value, only send it, but the type system is unable to see it. This is essentially the same question that I remember appeared in this forum "how to send a `Rc` to another thread when I know it has no other references". Nothing special to `FnOnce` except that we, the humans, can prove it is always sound. So why not do what was recommended in the `Rc` case and use an `unsafe` wrapper that implements `Sync` to move it the thread? Especially when the details around the soundness of this are so subtle.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [April 14, 2022, 11:49am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/11 "2022-04-14T11:49:57Z")

</div>

Why should `dyn FnOnce` specifically have this magic? For another example `dyn Future` also has no `&self` operations available.

Instead of using any magic you can do this using user code trivially, see [`SyncWrapper`](https://docs.rs/sync_wrapper/latest/sync_wrapper/struct.SyncWrapper.html) which can generically allow passing non-`Sync` data around as `Sync` by blocking all `&self` access.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [April 14, 2022, 12:23pm UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/12 "2022-04-14T12:23:25Z")

</div>

> [@chrefr](#):
>
> You essentially want to work around a limitation of the type system. You don't really share the value, only send it, but the type system is unable to see it. This is essentially the same question that I remember appeared in this forum "how to send a `Rc` to another thread when I know it has no other references". Nothing special to `FnOnce` except that we, the humans, can prove it is always sound. So why not do what was recommended in the `Rc` case and use an `unsafe` wrapper that implements `Sync` to move it the thread? Especially when the details around the soundness of this are so subtle.

It is different from that since `Rc` is not `Send`.

Basically what @kvark is looking for is a "channel" to "send" a piece of data from one thread to another -- `Send` should be enough. However, they are using `Arc` for this purpose, which requires `T: Sync` for `Arc<T>: Send` (and for good reasons). I think what you'd really want here is a different data structure, something more like `mpsc::sync_channel(1)`.

---

<div class="post-metadata">

**Author:** ![kvark](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kvark/32/645_2.png) [@kvark](https://internals.rust-lang.org/u/kvark)\
**Post date:** [April 14, 2022, 5:21pm UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/13 "2022-04-14T17:21:25Z")

</div>

> [@chrefr](#):
>
> Oh I got it, I think. But it already requires `Send` to be useful, so why not write the `Sync` explicitly too?

I don't want my API to constrain more than necessary. It's a task system. Send is assumed, since tasks are executed on other threads. But Sync makes no sense there.

> So why not do what was recommended in the `Rc` case and use an `unsafe` wrapper that implements `Sync` to move it the thread?

This is what I'm doing currently - [Lift Sync requirement by kvark · Pull Request #3 · kvark/choir · GitHub](https://github.com/kvark/choir/pull/3)

And it's all fine, technically, since unsafety is totally private to the implementation. However, there are some forces/people in the community that really frown upon unsafe code. I.e. having this single `unsafe` means I can no longer cater to the group of people who prefer "no unsafe". See [TinyVec](https://www.reddit.com/r/rust/comments/fshuhk/introducing_tinyvec_100_safe_alternative_to/) for example.

> Why should `dyn FnOnce` specifically have this magic? For another example `dyn Future` also has no `&self` operations available.

The question is a bit different. It's whether or not Rust compiler (or the standard library) allow for these specific rules to be written. If it does, then I think it would make sense to encode those extra rules, making `dyn Future` and `dyn FnOnce` more useful in safe code. If the rules are non-writable, then we can just go home and put `unsafe` in our code.

@RalfJungI'm using `Arc` because I really need reference counting there, in addition to sending it across. A task is only extracted via `Arc::try_unwrap` if it has no live dependencies, which is when it can be scheduled for execution. I don't believe this usecase is begging for anything different than `Arc`.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [April 14, 2022, 5:36pm UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/14 "2022-04-14T17:36:24Z")

</div>

> [@kvark](#):
>
> I'm using `Arc` because I really need reference counting there, in addition to sending it across. A task is only extracted via `Arc::try_unwrap` if it has no live dependencies, which is when it can be scheduled for execution. I don't believe this usecase is begging for anything different than `Arc` .

`Arc` has `deref`, and that's why we need `T: Sync` for `Arc<T>: Send`. It seems like you don't need `deref` for your type, you only need `try_unwrap`. So to me that sounds like you don't want `Arc`, you want something more targeted. (Maybe `Arc<SyncWrapper<T>>` is good enough though.)

---

<div class="post-metadata">

**Author:** ![kvark](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kvark/32/645_2.png) [@kvark](https://internals.rust-lang.org/u/kvark)\
**Post date:** [April 14, 2022, 6:06pm UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/15 "2022-04-14T18:06:47Z")

</div>

> [@RalfJung](#):
>
> `Arc` has `deref` , and that's why we need `T: Sync` for `Arc<T>: Send` .

I guess that's another way to look at this. I could work with `Arc` without `Deref`. Technically, what Arc could do is having the `Deref` [require `T: Sync`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=75c965dd52f28acfd1bd8f02a450a7e2).

That would mean I could use `Arc` normally on a non-sync data as long as I don't deref it. And it looks like the compiler would be happy with such an implementation (based on my playground sample). Is there any reason to not do it in std?

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [April 14, 2022, 6:19pm UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/16 "2022-04-14T18:19:46Z")

</div>

That might work. (There might be more operations that also need that bound. Basically everything that hands out a `&T`.)

I wonder what that would do to our `Arc` soundness proof in RustBelt...

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [April 14, 2022, 6:37pm UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/17 "2022-04-14T18:37:21Z")

</div>

> [@kvark](#):
>
> Technically, what Arc could do is having the `Deref` [require `T: Sync`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=75c965dd52f28acfd1bd8f02a450a7e2).

That would be a breaking change, because you can already `Arc::new` with `!Sync` types and use most of the methods and trait implementations, including `Deref`. The only place we currently require `T: Sync + Send` at all is for `Arc<T>`'s own `Sync` and `Send`.

---

<div class="post-metadata">

**Author:** ![kvark](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kvark/32/645_2.png) [@kvark](https://internals.rust-lang.org/u/kvark)\
**Post date:** [April 14, 2022, 7:54pm UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/18 "2022-04-14T19:54:23Z")

</div>

Ok, all in all, our discussion concluded in 3 different solutions:

1. use unsafe code (or other library with unsafe code), since the compiler doesn't see far enough
2. investigate it the compiler can make `dyn FnOnce: Sync`
3. investigate if `Arc` can soften up its bounds

I've already done (1) on my end. What would be the next steps about (2) and/or (3)? Filing an RFC? Making a PR into Rust?

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [April 14, 2022, 11:30pm UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/19 "2022-04-14T23:30:42Z")

</div>

Hmm, maybe we can just do this in `core`, without compiler help:

```rust
unsafe impl<'a, Args, Output> Sync for dyn FnOnce<Args, Output = Output> + 'a {}
unsafe impl<'a, Args, Output> Sync for dyn FnOnce<Args, Output = Output> + Send + 'a {}

unsafe impl<'a, Args, Output> Sync for dyn FnMut<Args, Output = Output> + 'a {}
unsafe impl<'a, Args, Output> Sync for dyn FnMut<Args, Output = Output> + Send + 'a {}

```

The compiler does accept that, but I don't know if there are any caveats.

In general, I think something like `SyncWrapper` is fine though.

---

<div class="post-metadata">

**Author:** ![elidupree](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/elidupree/32/4304_2.png) [@elidupree](https://internals.rust-lang.org/u/elidupree)\
**Post date:** [April 15, 2022, 1:24am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/20 "2022-04-15T01:24:15Z")

</div>

In current Rust, is there any rule that would forbid someone from writing unsafe code to downcast a `&dyn Trait` into a `&ConcreteType`, if the programmer can prove that the trait object is of that concrete type? It seems like that is something that a person might expect to be allowed to do using unsafe code, and adding this Sync impl would deny that.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [April 15, 2022, 1:56am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/21 "2022-04-15T01:56:39Z")

</div>

No, and this is exactly what `Any` is automating. What this is taking advantage of to be sound, though, is that the `Fn*` traits can't be implemented manually for a known/nonopaque type.

Adding those impls would either tie the `Fn*` traits to either be unsafe (you must maintain this property manually) or magicked by the compiler to only ever be implemented for types where this impl is sound.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [April 15, 2022, 3:29am UTC](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470/22 "2022-04-15T03:29:51Z")

</div>

I feel like I'm missing something obvious, but how do you get a `dyn Any` from a `dyn FnOnce`? I thought you needed the trait to explicitly support something like `as_any`? Or even with bespoke `unsafe` code, wouldn't you need a way to dig out a `TypeId` or similar?

Hmm, or maybe you mean a more mundane pointer comparison -- "Pointer 0xF00123 is in my collection of known `Foo` pointers, so cast it!"

[Next page](https://internals.rust-lang.org/t/dyn-fnonce-should-always-be-sync/16470.md?page=2)
