An approach to resolving some issues with optional arguments

The approach which makes the most sense (to me) is just to have each default be a const item. The default is const evaluated, and then calling the function without a default argument is just sugar for foo(arg, DEFAULT_ARG). There's no question about what the semantics of such a feature would be.

The actual blocker is more on other interesting questions/limitations:

  • Can you use fn foo(u32, u32=0) as fn(u32)? As impl Fn(u32)?
  • Can you default non-tail arguments? How much of std is going to feel second-class because its arguments were put in the wrong order for defaulting?
  • Everywhere else fields are elided, we use .. to indicate that things are missing, why is function defaults different?
  • How do argument defaults interact with traits?
  • What about defaulting arguments of generic type?

There's a number of unanswered questions, along with whether we actually want default arguments, or if we'd be better served by supporting the arguments struct pattern more directly. Default arguments have a tendency to lead to functions with a ton of defaulted arguments, and putting them in a struct makes for cleaner expansion and named (field) arguments.

In a future Rust, I envision something like

// pretend this is an impl
fn Database::new(struct {
    port: Ip,
    file: File,
    trace_span = None::<Span>,
    config = Config::default(),
    ..
});

If we had something like this, there's much less need for default arguments.

8 Likes