2

Given the following struct Foo<T> that derives Default:

#[derive(Default)]
struct Foo<T> {
    bar: Option<T>,
}

Why does this compile

fn create<T>() -> Foo<T> {
    Foo {
        bar: Option::default(),
    }
}

but this doesn't?

fn create_alt<T>() -> Foo<T> {
    Foo::default()
}

In my mind they are both doing the exact same thing--it shouldn't matter if T implements Default (which is what the compiler wants me to specify) because Option<T> implements Default.

Here is a link to the Rust Playground with this example.

Brian
  • 149
  • 1
  • 7
  • Note that this happens to several other automatically derivable traits, including `Debug`, `Default`, `Clone`, and possibly more. The derived implementations require that all type parameters also implement them. – E_net4 Sep 06 '17 at 16:53

1 Answers1

2

This is a known issue, and it's hard to fix. Issue #26925

In short, #[derive] uses incorrect bounds: it assumes that in order to implement Default for Foo<T>, T must be Default, when in reality Option<T>: Default is sufficient.

The problem with fixing it is that it's possible to have struct members of private types, and using #[derive] on a public generic struct that has private members could partially expose that private interface. For example,

trait MyTrait {}

struct MyType<T> {}

impl<T> Default for MyType<T> where T: MyTrait {}

#[derive(Default)]
pub struct PubType<T> {
    member: MyType<T>,
}

If #[derive(Default)] does the right thing, you effectively have this impl block for a public type that exposes a private trait:

impl Default for PubType<T>
    where T: MyTrait
{ ... }

Probably the best way to get around this right now is to avoid using #[derive] in this case and write the impl yourself.

mcarton
  • 27,633
  • 5
  • 85
  • 95
trent
  • 25,033
  • 7
  • 51
  • 90