rust-derive-builder icon indicating copy to clipboard operation
rust-derive-builder copied to clipboard

generic fields cannot be defaulted (or skipped)

Open colin-kiegel opened this issue 7 years ago • 3 comments

#[derive(Builder)]
struct Generic<T> {
    #[builder(setter(skip))] // <-- implicit default
    pub ipsum: T,
    #[builder(default)] // <-- explicit default
    pub dolor: T,
}

fails with

error[E0277]: the trait bound `T: std::default::Default` is not satisfied
|
| #[derive(Builder)]
|          ^^^^^^^ the trait `std::default::Default` is not implemented for `T` 
= help: consider adding a `where T: std::default::Default` bound
= note: required by `std::default::Default::default`

colin-kiegel avatar Apr 26 '17 15:04 colin-kiegel

The reason is that we never emit bounds like T: Default (cmp. #91)

Current workarounds are:

  • add a T: Default bound on the target type (e.g. struct Generic<T: Default>)
  • use a custom default #[builder(default="magic_generic_fn_in_scope()")]

colin-kiegel avatar Apr 26 '17 15:04 colin-kiegel

I looked at this when fixing #91, but I couldn't find a way to express "this is fine if a) a struct-level default was specified, b) an explicit field-level default was specified, or c) this field was set explicitly at runtime" which made me suspect it's not possible to handle ergonomically through the type system.

TedDriggs avatar Apr 26 '17 19:04 TedDriggs

This is even worse when we have something like:

Generic<T> {
list: Vec<T>
}

Where for certain cases I know T does not implement Default, so I can't enforce it, however obviously Vec<T> does... For such generic types, I can not even use the builder.

botev avatar Mar 23 '18 16:03 botev

Using an explicit default seems like a simple enough workaround that we don’t need to keep this issue open.

TedDriggs avatar Nov 08 '22 11:11 TedDriggs