Rust doesn’t have named/keyword arguments yet, and there has already been several RFCs and discussions about it over hundreds of posts long. I admit I did not read most of that, so if I’m just repeating what had already been said, feel free to point me to the relevant discussions.
Motivation
The core idea is that I think Rust’s structs and enums are already quite good for expressing APIs, if only they could be a little more ergonomic (less boilerplate).
Consider, for example, an API like this:
pub enum FooColor { Red, Green, Blue }
pub struct FooArgs<'a> {
pub alpha: &'a str,
pub color: FooColor,
#[doc(hidden)]
pub __reserved: (),
}
impl<'a> Default for FooArgs<'a> { … }
fn foo(args: FooArgs) { … }
On the user side, they would have to use it like this:
use some_mod::{FooArgs, FooColor, foo};
foo(FooArgs {
alpha: "blah",
color: FooColor::Red,
.. Default::default()
})
There is quite a bit of redundancy in this code that would be nice to eliminate:
-
FooArgs
andFooColor
both need to be brought in scope, but this feels rather wasteful if both are specific to thefoo()
API. -
FooArgs
needs to be mentioned explicitly, even though it’s clear from the context that the only acceptable struct isFooArgs
. -
FooColor::
needs to be prepended to the enum value, at least if you don’t want to pollute the namespace with highly generic names (Red
,Green
, andBlue
). -
Default::default()
is a pretty long expression to type out every time you want to callfoo
!
It would be nice if the user’s code could be simplified to just:
use some_mod::foo;
foo(_ {
alpha: "blah",
color: _::Red,
..
})
Idea
Specifically what we have done here are:
-
Struct name omission (see also: phaylon’s idea): Automatically infer the struct type in
_ { … }
if there is sufficient information from the surrounding context. (The reason for not allowing just{ … }
is that it would be hard to parse.)Beyond the use case above, it would also encourage the use of structs over tuples in general, leading to more readable code.
This idea could also be extended to patterns.
-
Enum name omission: Automatically infer the enum type in
_::Whatever(…)
if there is sufficient information from the surrounding context. (The reason for_::
is to avoid ambiguities ifWhatever
is a function in scope.)Beyond the use case above, it would also encourage the use of domain-specific enums over generic enums (
Option
,Result
), leading to more readable code.This idea could also be extended to patterns.
-
Default struct update (see also: pnkfelix’s idea): Allow
SomeStruct { … .. Default::default() }
to be shortened to
SomeStruct { … .. }
This idea helps mostly the users of the library. One could devise ways to help the library writers too, but that is beyond the scope of this post.
Downsides
Syntactically, this adds three new subtle changes. Of the three, I think _::
might be most controversial, since it is possible that this syntax might be used for some other feature in the future. Alternatively, one could add an enum
prefix or something else.
The new syntax is also arguably more punctuation heavy, partly because of the use of _
and also because we killed off a lot of the unnecessary words.
The biggest changes here are not so much the syntax however: the type inference algorithm would become more complicated and less elegant as a result of this change. There would be more situations where the type of this value must be known in this context
. However, the change is backward compatible, and should not alter the inference of existing code.