Named arguments increase readability a lot

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).

4 Likes