Default trait for Custom trait in Box<dyn Trait>

Hi, I'm trying to define a trait, that includes an option to create it self, and do an operation, to then use all structs that implements the trait with their respective functions:

pub trait Stat {
    fn foo(&mut self, value: f64);
    fn default() -> Box<Self>;
}

pub struct Adder(f64);

impl Stat for Adder {
    fn foo(&mut self, value: f64) {
        self.0 += value;
    }

    fn default() -> Box<Self> {
        Box::new(Self(0.0))
    }
}

fn main(a: Box<dyn Stat>, b: Box<dyn Stat>) {
    let s: Box<dyn Stat> = Adder::default();
    s.foo(10.0);
    a.foo(10.0);
    b.foo(10.0);
}

But I know this is not allowed.... a safe Trait can not use Self as a return value.... but how can I achieve something similar? have the trait it self as return with dyn is also not allowed....

Thx!

This is not true. Maybe you meant "object-safe"?


Your code in the Playground can be fixed by restricting the default() method to non-trait-objects, using the where Self: Sized clause on the method. That'll allow you to create an instance of the type as long as it's not a trait object.

If you want a default value for the concrete type Box<dyn Stat>, then you'll have to supply a specific type to serve as the underlying, statically-typed value. You can do that by adding an impl block to dyn Stat, just like you would do with any other type that you created.

Playground with both ideas.

3 Likes

Hi, there is some issues with the solution, impl in the Trait, you are using the struct Adder to construct the default value, while it should be Self, only that changes causes a lot of things to be handled that I still don't know very well how to do it.

Each Struct need to have its own way to foo and default.

There isn't, you just don't understand it.

They already have. The ::new() inherent impl is independent of the trait. It's an inherent function on the dyn Stat types.

Here's the code without the new() function on dyn Stat.

There's no such thing as conjuring a dyn Trait from thin air, without an underlying concrete type. It just doesn't make any sense. A dyn Trait must be coerced from a static type that implements the trait. This is exactly what I was explaining in my previous post.

mmm, why this works? Check this: Traits - The Rust Reference

The error I got, says the object must be safe, and in the restrictions is not be Sized.

The doc says:

  • All associated functions must either be dispatchable from a trait object or be explicitly non-dispatchable:
    ...
  • Explicitly non-dispatchable functions require:
    • Have a where Self: Sized bound (receiver type of Self (i.e. self) implies this).

So by adding where Self: Sized you can create a trait object for the trait, but the trait object will not allow calling that one method. That method can still be called for a regular (not dyn) implementation of the trait.

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.