Supporting ..Default::default() in non-Default structs?

Say you have a struct

struct MyStruct {
    val_a: TypeA, // Implements Default
    val_b: TypeB, // Implements Default
    val_c: TypeC, // Does NOT implement Default
}

Is there an intentional reason why we couldn't still support

let my_struct = MyStruct {
    val_c: TypeC::new(/* args */),
    ..Default::default()
};

given that the omitted fields all themselves implement Default even though the parent struct doesn't? I found some prior discussion on the documentation surrounding this, but didn't see much about what it would take to actually support it. Is there prior art here?

You'd probably be interested in


As for FRU, I think the core problem is that it's just not doing what most people think it's doing, and we should add a new construct that does. See, for example, https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/Take.20N.2B1.3A.20.60.23.5Bnon_exhaustive.28.24vis.29.5D.60/near/493484904

3 Likes

Hm, that RFC is interesting but I think it addresses a different use case here. The one I'm talking about is where a struct can't be Default because some of its fields need values known only at runtime (so they can't be set in the struct declaration itself), but where most of its fields are Default and could be omitted for their redundancy. Adding default field values is certainly handy, but only useful for compile-time values. I've seen this come up at times in builder patterns for example.

EDIT: The Zulip chat gets closer to what I mean here, though that still requires Default for the initialization. In this sense I think the spirit of the FRU syntax isn't necessarily wrong if it actually could be what it looks like in terms of being a fold/spread operation over the unmentioned/omitted fields.

Or some sort of alternative:

let my_struct = MyStruct {
    val_c: TypeC::new(/* args */),
    _: Default::default(),
};

The RFC allows that! You can specify the defaults for everything that can be set in the declaration, then when you use the literal you have to set those fields without defaults, but can still , .. } to get all the other defaults.

Unless you mean that they're Default but not const Default?

1 Like

Ah, yes, after looking at it again, it seems to cover this use case.

#![feature(default_field_values)]

pub struct NotDefault(pub u32);

pub struct MyStruct {
    pub val_a: u32 = 10,
    pub val_b: NotDefault,
}

pub fn build(val: u32) -> MyStruct {
    MyStruct {
        val_b: NotDefault(val),
        ..
    }
}

Compiles just fine on nightly. Thanks! Glad to see this is in the works.

3 Likes

When implementing Default for a large struct when only 1 field has something that can't be derived, others must be field_x: Default::default(). You can't use .. Default:: default(), because you are implementing it...

In this case I was asking if this limitation (it can result in a lot of redundant Default::default() lines) has been discussed before, and it looks like RFC 3681 does plan to provide an improvement on the ergonomics here. So, problem solved!

Default field values RFC is very interesting, but it is focused just on Default values.

If we wish more flexibility, than we could pay more attention on Partial Types RFC: