3

Playground

#[derive(Default)]
struct Bar;

#[derive(Default)]
struct Baz;

fn main() {
    let mut vec = Vec::<Box<dyn Default>>::new();
//                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::default::Default` cannot be made into an object
    vec.push(Box::new(Bar));
    vec.push(Box::new(Baz));
}

Default is a sized Trait, which means you cannot convert it to a trait object.

For the example above, is there a workaround so I can store sized traits in a Vec (or any other collection)?

Boiethios
  • 38,438
  • 19
  • 134
  • 183
hellow
  • 12,430
  • 7
  • 56
  • 79
  • I don't think that there're any workarounds. What's the point of having a vector of Defaults? How should it even work? – ozkriff Aug 20 '18 at 06:34
  • You could call the method provided by the trait (in this case `default`), like with any other trait too. – hellow Aug 20 '18 at 06:38
  • You want to make a factory ? – Stargateur Aug 20 '18 at 07:07
  • 1
    @hellow it's a factory function that doesn't take `self`. There's no point in trying to call it with some already existing object like `obj.default()`. – ozkriff Aug 20 '18 at 07:18
  • @ozkriff I have added this point to my answer – Boiethios Aug 20 '18 at 07:24
  • Damn... You're right. How am I supposed to call a "constructor" on a already created object... Valid point! Thanks, for making me to understand this. – hellow Aug 20 '18 at 07:34

1 Answers1

5

You cannot do such a thing because of the object safety rule. This rule says that a trait which a method returns the concrete type itself cannot be made into a trait object. The reason is that the trait object would have known the concrete type.

Also, this trait has no method (a function that takes self), so there is no point to make a trait object from it.

See more about this rule here, there and in this blog article.

See also this question.


This rule is pretty intuitive: what do you expect your code to do?

#[derive(Default)]
struct Bar;

#[derive(Default)]
struct Baz;

fn main() {
    let mut vec = Vec::<Box<dyn Default>>::new();
    vec.push(Box::new(Bar));
    vec.push(Box::new(Baz));

    vec.first().unwrap()::new();
    // Whatever the syntax should be, what do you expect this to return?
    // This type cannot be know at compile time.
}
Boiethios
  • 38,438
  • 19
  • 134
  • 183
  • 1
    How often I've wished that the rule was the other way around: ie, allow such traits to be boxed, etc... but only allow access to the subset of their interface which is object safe. – Matthieu M. Aug 20 '18 at 13:00
  • @MatthieuM. I think this is possible and that would be retrocompatible. Let's do an RFC ;) – Boiethios Aug 20 '18 at 14:14