<ident>: <expr>
is used only in structs and <pat>: <type>
is more prevalent. So if named arguments will not be tied to structs (like in this proposal or in the pub
ones), then I think it will be a false consistency, which should not be followed.
Type ascription is useful for picking or coercing a type for a generic function.
let a = &b"1234";
f(a: &[u8]) // instead of `f(a as &[u8])` or `f::<[u8]>(a)`
I don't see any part in Rust supporting named arguments using :
. The closest match is println!("{foo}", foo=4)
which uses =
.
Or just let a: &[u8] = b"1234"
. Because it's a variable, there's somewhere else to put the type, which would be more idiomatic in any case.
I think named arguments are very analogous to structs even if they aren't structs themselves.
Also, the alternative syntax suggested in the OP has the severe downside of looking like lifetimes while being completely unrelated. Both lifetimes and (independently) the syntax Rust uses for lifetimes have a reputation for being confusing to newcomers; no need to further conflate things. Beyond name: value
, other familiar-seeming options are name => value
and (notwithstanding the OP's valid points about editions) name = value
, though, again, I think the inconsistency with structs makes them worse than name: value
.
but perhaps i do want to retain the more specific type a: &[u8; 4]
.
or maybe a
is not a local variable, but a function argument or static variable which you can't control.
you also can't just "carve out" $ident :
and keep the remaining $expr :
for type ascription use, since it makes f(a: T)
and f(&b: T)
having different semantics, which violates the consistency even worse.
in any case i don't support sacrificing type ascription for named arguments.
I like the idea in general, but syntactical association with lifetimes is problematic. Lifetimes are the scariest most confusing part of the language, so I don't think Rust can afford reusing that syntax for something else.
Maybe a different sigil?
foo(@c = 5, @b = 3, @a = 1);
foo($c = 5, $b = 3, $a = 1);
foo(^c = 5, ^b = 3, ^a = 1);
foo(#c = 5, #b = 3, #a = 1);
foo(.c = 5, .b = 3, .a = 1);
I like the leading point (.
) because, for me, it implies that the following parameter name is interpreted with respect to the called function name. It's clearly not method syntax, but for me it does have a somewhat-similar mental model of name scope.
On a related note I'm worried that this will make the visual ambiguity between lifetimes and character constants worse. Right now, lifetime 'a
is only used inside a type parameter list <...>
, and character constant 'a'
never appears in that context. But with this change, now we can have either of them inside function argument lists. I trust that the parser can handle it, but for people reading unfamiliar code,
foo('a = 23)
is going to cause a mental hiccup as they try to figure out whether that wasn't supposed to be
foo('a', 23)
or something like that. And vice versa.
You're right, that could also cause problems with autocomplete (e.g. when typing '
and the IDE adds another '
).
I like the idea of using .arg
, since the dot is quite unobtrusive (#arg
would add more visual clutter). Please tell me what you think, so I can update the proposal.
I also like the .arg
suggestion.
I re-read the RFC by mentally replacing 'arg
by .arg
and I think that the result is great.
With the introduction of const generics you'll be able to pass chars as const arguments, I don't know how often you would see char
const parameters though (so this might be a moot point).
#![feature(const_generics)]
pub fn foo<const BAR: char>(){}
fn main(){
foo::<'a'>();
}
I think I'll also replace the =
with :
to be more similar to struct syntax:
free_fall(.z0: 100.0, .v0: 0.0, .g: 9.81);
.
+ :
that's a lot of dots
I think I prefer =
. It's also safer in case type ascription ever gets stabilized.
Since we are all bikeshedding syntax here, how about...
foo(a := 3)
Yes, it's a brand new composed sigil - but it's something people expect to have something to do with binding.
Another option is:
foo(a => 3)
If we borrowed block syntax from Ruby, why not that?
Which is probably not possible to add to Rust (at least not for a long time) because it breaks macro_rules!
matchers.
Why? Because they'll parse them as two sigils? How about keeping them two sigils but formatting them without a space between them?
"What should be the syntax" is probably the least important problem with named arguments. This is yet another RFC that proposes a new syntax but completely fails to address the many questions that had been raised before. More syntax is not what we need for a good named arguments proposal, fleshing out details of semantics is.
Is there a sum-up of those concerns somewhere?
@H2CO3 in an unrelated note, I want to thank you for keeping track of the general direction of Rust, and say "no" when needed. Rust is such a good language, in part due to all the "no" that have been said in the past. I personally would love any kind of named arguments, but they should not have drawbacks to current and future extensions.
This post was my attempt at a 10,000 foot view summary, and given the number of <3s on it I assume people feel it's at least vaguely accurate. But it's probably more concise than what you're after. I think the rest of that thread did a decent job fleshing out some parts of it, but certainly not all, and this new thread is kinda not touching on any of it except syntax (I hadn't posted in this thread before because there's only so many times I can say "this is all academic bikeshedding; you're missing the real problems" before it starts sounding rude even to myself).
But we're definitely missing a proper summary of these issues, like I did for orphan rules issues a while back. It'd take someone more interested in named arguments than me to make one.
I would like to discuss the more important concerns more, but so far almost no concerns besides the syntax were raised.
@lxrec I read your summary, and I believe that my RFC addresses most of the points you raised. I will further extend the Motivation section later today, to discuss why I believe enums and newtypes aren't sufficent.