From 42c53ca2226d0f74b8b3ce5d34d71a7ce5c2d637 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Sat, 4 Nov 2023 08:43:11 -0700 Subject: [PATCH] C-SEND-SYNC: Discuss trait objects. 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. --- src/interoperability.md | 57 +++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/interoperability.md b/src/interoperability.md index 7a505f4..db3493c 100644 --- a/src/interoperability.md +++ b/src/interoperability.md @@ -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() {} - assert_send::(); -} - -#[test] -fn test_sync() { - fn assert_sync() {} - assert_sync::(); -} -``` +- 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 + 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() {} + assert_send::(); + } + + #[test] + fn test_sync() { + fn assert_sync() {} + assert_sync::(); + } + ```