How to use dyn trait wrapped with Mutex

I met a problem when I use dyn trait wrapped with Mutex

use std::sync::Mutex;

trait Bar {}
struct Foo {}
impl Bar for Foo {}

fn foo(_: Box<dyn Bar>) {}
fn foo_mutex(_: Mutex<Box<dyn Bar>>) {}

fn main() {
  //OK
  let a = Box::new(Foo{});
  foo(a);

  //compile error
  let a = Mutex::new(a);
  foo_mutex(a);
}

It will compile error,

   |
17 |   foo_mutex(a);
   |             ^ expected trait object `dyn Bar`, found struct `Foo`
   |
   = note: expected struct `Mutex<Box<(dyn Bar + 'static)>>`
              found struct `Mutex<Box<Foo>>`

Here is playground

when I use Box<dyn trait> directly, everything works fine. But why does a compilation error occur once I use Mutex to wrapper it?

Any help will be appreciated, thanks

The function call foo(a) is accepted because Box<Foo> can be coerced to Box<dyn Bar>. This is called an unsizing coercion, and Box is one of a few types in std that support it (marked by the experimental CoerceUnsized trait). However, this coercion can only happen when you actually have an expression of type Box<Foo>. When the Box<Foo> is behind an indirection, like when it's contained in a Mutex<Box<Foo>>, you can't coerce it to Box<dyn Bar> anymore. This is for good reason, since (1) Mutex keeps its payload on the heap in a fixed-size allocation, and (2) Box<dyn Bar> is not the same size as Box<Foo>, the first being a fat pointer and the second a thin pointer; the backing allocation for the Mutex doesn't even have enough room to store a whole Box<dyn Bar>. [edit: this is wrong, Mutex stores its data inline not on the heap! but the compiler will not take advantage of this]

3 Likes

In light of @cole-miller’s response, in this case you need to manually coerce to a trait object

let a = Mutex::new(a as Box<dyn Bar>);
2 Likes

Cool. Thanks @cole-miller and @drewkett .
The detailed answer of @cole-miller further deepened my understanding of the Box<dyn trait>. Thanks again.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.