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
  • 139
  • 6
  • 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 - Krabbe mit Hüten 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
  • 24,420
  • 5
  • 70
  • 79
trent
  • 21,712
  • 7
  • 47
  • 79