Exposing `Box<dyn T>` vs use generic in a `new` method

What is the preferred way to create a struct with Box<dyn T> fields:

  • Requesting the Box<dyn T>
  • Using a generic type and boxing the value internally

They both seems equivalent. But the latter makes the API less verbose since the caller does not need to explicitly call Box::new.

trait MyTrait { /*some methods*/ }

struct MyStruct {
    value: Box<dyn MyTrait>,
}

impl MyStruct {
    fn new(value: Box<dyn MyTrait>) -> Self {
        Self { value }
    }

    /* OR */

    fn new<T> (value: T) -> Self
    where
        T: MyTrait
    {
        Self { value: Box::new(value) }
    }
}

From what I can tell, accepting Box<dyn Trait> directly is pretty rare and looks quite weird. I think you'd go with the generic approach by default. The generic approach is also more flexible in terms of forward compatibility: if you were to change your representation from Box<dyn Trait> to something else, there's little chance you could convert a Box<dyn Trait> to that something else, whereas this option for silently changing the implementation is still open if you use generics.

1 Like

In such situations I usually do neither:

impl MyStruct {
    fn new(value: impl MyTrait) -> Self {
        Self { value: Box::new(value) }
    }
}
1 Like

A limitation of accepting a generic and then boxing it is that if the caller already has Box<dyn MyTrait>, they can't pass it on.

1 Like

Argument-position impl Trait (APIT) is accepting a generic. It's like so but you can't name the trait or use turbofish:

impl MyStruct {
    fn new<T: MyTrait>(value: T) -> Self {
        Self { value: Box::new(value) }
    }
}
1 Like

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.