1

This code:

trait Trait {}

fn dont_require_send(ts: Vec<Box<dyn Trait>>) {}

fn use_send(ts: Vec<Box<dyn Trait + Send>>) {
    dont_require_send(ts)
}

fails with:

error[E0308]: mismatched types
 --> src/main.rs:6:23
  |
6 |     dont_require_send(ts)
  |                       ^^ expected trait `Trait`, found trait `Trait + std::marker::Send`
  |
  = note: expected type `std::vec::Vec<std::boxed::Box<Trait + 'static>>`
             found type `std::vec::Vec<std::boxed::Box<Trait + std::marker::Send + 'static>>`

I kind of understand that Rust considers Trait and Trait + Send to be different types, and that is probably the reason for the error. On the other hand, I can't think of any reason why rejecting this particular code is actually useful. It is in fact quite annoying, it forces me to require Send in the dont_require_send function's parameters even though the function doesn't actually need it. Under some circumstances it could even make me implement several versions of dont_require_send for different combinations of these marker traits.

Is there any workaround for this? Or are there any plans in the Rust compiler itself to make this code compile?

EDIT

What I've extracted from the comments: This question is a duplicate of Is there any way to convert Box> to Box>?. Both ways suggested there to work around the nuisance work for my question as well.

  1. fn dont_require_send<U: Trait + ?Sized>(ts: Vec<Box<dyn U>>) {} is probably the best solution if you have access to dont_require_send's sources. I personally don't like how the original intent is obscured, so I'm probably going to use this new idiom rarely.
  2. If you don't have access to the original source, you can use the following to convert the objects at the call site: ts.into_iter().map(|t| t as Box<Trait>).collect();. Please note that just naively using the box-unbox trick from the other question doesn't work (why?): dont_require_send(ts.into_iter().map(|t| Box::new(*t)).collect())
Tomáš Dvořák
  • 1,490
  • 1
  • 9
  • 20
  • 2
    `fn dont_require_send(us: Vec>)` – trent Jul 30 '18 at 18:38
  • It's not `Trait` vs. `Trait + Send`, it's `Box` vs. `Box`. Those types have different memory layout. – mcarton Jul 30 '18 at 18:42
  • 1
    I believe your question is answered by the answers of [Is there any way to convert Box> to Box>?](https://stackoverflow.com/q/51447656/155423). If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jul 30 '18 at 18:45
  • I've tried to apply the box-unbox solution from the sibling question this way: `dont_require_send(ts.into_iter().map(|t| Box::new(*t)).collect())`, but it doesn't compile (https://play.rust-lang.org/?gist=5907326f328f91e4a294145dfb6d8035&version=stable&mode=debug&edition=2015). Also, I'm still uncertain if this restriction is useful, and if not, is there some hope this could work automatically in the future? – Tomáš Dvořák Jul 30 '18 at 19:31
  • @TomášDvořák I don't believe that Stack Overflow is a good place to ask questions like "will language *X* ever support *some feature*". If you want something like that, it seems better to ask somewhere like the [user's forum](https://users.rust-lang.org/), [internals forum](https://internals.rust-lang.org/), or the issue tracker. – Shepmaster Jul 30 '18 at 19:36
  • [The duplicate applied to your case](https://play.rust-lang.org/?gist=5cb40391f33c4ae1e68d9780cf42d7f5&version=stable&mode=debug&edition=2015) — you don't have to unbox in this case because `into_iter` removes the outer layer. – Shepmaster Jul 30 '18 at 19:40
  • In your case, [Shepmaster's answer to the other question](https://stackoverflow.com/a/51451932/3650362) may be more appropriate than the unbox-box one. [Here it is applied to your problem](https://play.rust-lang.org/?gist=5907326f328f91e4a294145dfb6d8035&version=stable&mode=debug&edition=2015). – trent Jul 30 '18 at 20:08
  • Thank you for your suggestions. In the end, in my app, I've decided to use `fn dont_require_send(ts: Vec>)`, it's probably the least annoying way for my use case. @trentcl's `U: T + ?Sized` is nice, but it obscures the purpose too much for my taste (`dyn` keyword gone etc.), and @Shepmaster's `ts.into_iter().map(|t| t as Box).collect()` is also nice, but I'd have to do that at every call site. It's good to know there are workarounds in case I really need them, though. Thank you. – Tomáš Dvořák Jul 30 '18 at 21:04
  • From the comments it seems to me that the most versatile solution is the ``. I'd like to hear from more experienced Rustaceans: Is that a common idiom, something people who know it routinely use when writing libraries to allow users of the library to use it with any combination of marker traits? And when you see it, do you immediately recognize it as a pattern to allow that? Are there any downsides to this idiom besides readability for those uninitiated? – Tomáš Dvořák Jul 31 '18 at 04:43

0 Answers0