Skip to content

Commit

Permalink
C-SEND-SYNC: Discuss trait objects.
Browse files Browse the repository at this point in the history
The previous text only discussed raw pointers, but trait objects are another common situation where authors may accidentally design overly restrictive APIs, so I think that discussing them here is appropriate.
  • Loading branch information
kpreid authored Nov 4, 2023
1 parent e0e515b commit 42c53ca
Showing 1 changed file with 38 additions and 19 deletions.
57 changes: 38 additions & 19 deletions src/interoperability.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,29 +161,48 @@ pub struct T { /* ... */ }
## Types are `Send` and `Sync` where possible (C-SEND-SYNC)

[`Send`] and [`Sync`] are automatically implemented when the compiler determines
it is appropriate.
it is appropriate. However, the compiler cannot automatically determine this in
two notable cases: trait objects and raw pointers.

[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html

In types that manipulate raw pointers, be vigilant that the `Send` and `Sync`
status of your type accurately reflects its thread safety characteristics. Tests
like the following can help catch unintentional regressions in whether the type
implements `Send` or `Sync`.

```rust
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<MyStrangeType>();
}

#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<MyStrangeType>();
}
```
- Trait object (`dyn`) types only implement `Send` and `Sync` if they specify
those traits, or one of the specified traits has them as supertraits.
Therefore, if a type contains a trait object, it must opt in to being `Send`,
`Sync`, or both, as appropriate:

```rust
struct MyDataSource {
source: Box<dyn Iterator<Item = f64> + Send>,
}
```

Note that this also requires *all* types which are coerced to the trait object
type to implement `Send`, which may be an undesirable restriction. For this
reason, it may be preferable to choose generics over trait objects, which
allows the containing type to be `Send` and/or `Sync` when the contents are;
but this is a decision with many other factors that are outside the scope of
this document.

- In types that manipulate raw pointers, be vigilant that the `Send` and `Sync`
status of your type accurately reflects its thread safety characteristics.
Tests like the following can help catch unintentional regressions in whether
the type implements `Send` or `Sync`.

```rust
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<MyStrangeType>();
}

#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<MyStrangeType>();
}
```


<a id="c-good-err"></a>
Expand Down

0 comments on commit 42c53ca

Please sign in to comment.