I would envision something like:
fn foo(_ { bar: usize, baz: usize = 42 }) {}
fn main() {
foo(_ { bar: 3, ..default });
}
This is a combination of two/three changes: "anonymous structs" (which wouldn't be strictly necessary), "struct name inference" where you don't have to name the struct and use only a pattern instead, and "default as keyword" where we bless default
as a context dependent keyword that expands to Default::default()
.
This approach has in my eyes the following benefits:
- it fits the rest of the language more naturally
- blesses the builder pattern into the language
- introduce features that can be used in other contexts instead of being its own thing exclusive to method calling
- it has a natural way for it being backwards and forward compatible with previous and new editions
On the last point, older compilers could call new methods the following way
// edition:2021
fn foo(_ { bar: usize, baz: usize = 42 }) {}
fn main() {
foo(_ { bar: 3, ..default });
}
// edition:2021 definition used in 2018
foo(foo_args { bar: 3, ..Default::default() });
// it wouldn't need to be `foo_args`, but it has to be *some* ident
// edition:2018 definition used in 2021
struct FooArgs {
bar: usize,
baz: usize,
}
impl Derive for FooArgs { /**/ }
fn foo(FooArgs { bar, baz }) {}
fn main() {
foo(_ { bar: 3, ..default });
}
If we were to go down this route we could/would need to also have:
struct FooArgs {
bar: usize,
baz: usize = 42,
}
I am waving my hands at the fact that bar
doesn't have a default value yet I am relying on Default
being implemented for the whole thing (this could be not a problem if the field's type is already Default
) or have some kind of PartialDefault
trait (that would need to be blessed into the language to actually work).