-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Reserve f(a = b)
in Rust 2018
#2443
Conversation
kennytm
commented
May 18, 2018
- Rendered
- Pre-RFC
Isn't the type ascription issue necessarily already solved for struct creation?
|
```rust | ||
macro_rules! call { ($e:expr) => { foo($e) } } | ||
call!(a = 1); | ||
// allowed, expands to `foo((a = 1))`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This gets into the "are macros tokens or not" question that I never understand. If the macro used a tt
instead of an expr
would it be invalid? Why did the macro expand to something with parens here?
I think the number of cases involved in the "not in these places" definition still has me inclined towards the "assignment is just a statement" alternative instead (with some things like "match arms can be any statement", perhaps).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@scottmcm Yes if it is expanded via :tt
instead of :expr
it would be invalid.
"Something with parenthesis" is already the existing behavior of :expr
. Compare:
macro_rules! a {
(expr: $e:expr) => { 3 * $e };
(tts: $($t:tt)*) => { 3 * $($t)* };
}
fn main() {
println!("{}", a!(expr: 7 + 13)); // 60
println!("{}", a!(tts: 7 + 13)); // 34
}
from all editions (including 2015 and 2018), i.e. the syntax `f(a = b)` should be unreserved: | ||
|
||
1. We decided to permanently reject named arguments, or | ||
2. We accepted named arguments but have chosen a different syntax (e.g. `f(a: b)`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great section! Thanks for including it.
Foo { a: f64 } // Also not sure if the field pun form works This compiles, but probably doesn't do what you were thinking: rust-lang/rust-clippy#2676 |
@burdges No you can't place an arbitrary expression in a struct literal, e.g. |
I'm surprised if |
You are not alone: https://internals.rust-lang.org/t/suggestion-references-in-struct-literal/6789 |
I do think it's worth linting against this, if only because it looks confusing to use an assignment expression as a function argument. (And since assignment returns |
I've originally expressed concerns with this very change in the internals thread but since then changed my opinion. I still do not like named arguments, but |
Although this is technically off-topic, @est31 Are your objections to named arguments (regardless of syntax) written down anywhere? I'm completely unaware of what they might be and have never seen anyone else claim they're an undesirable feature (as opposed to a low priority). |
@Ixrec I'll reply to your question on the thread that @steveklabnik linked. Don't want this thread to become a discussion of the feature itself. |
@joshtriplett Why? Do you think named arguments are a bad idea, object to this particular syntax, or want to avoid breaking the use of assignments in function calls? |
I personally value consistency, and to disallow this syntax in one specific case goes against that. There are plenty of syntaxes we could use instead that won't require restrictions on existing constructs, so to me this is not a desirable change. |
I'm strongly in favour of named arguments, but I don't think we should be speculatively reserving syntax for it. We might settle on something else or decide not to have it at all. Or we might not work on it until after the next edition and we can reserve something then. In general, I don't think we should be using the edition to reserve keywords and syntax speculatively. If we have a firm plan and the timing works with an edition (e.g., |
I don't see what's wrong with this because:
mod aliases {
let one = 1;
let zero = 0;
// ...
let nil = (); // It is nil, right? I forgot the actual name
}
fn nilly_function() {
stuff1(()); // stuff1(aliases::nil);
stuff2(()); // stuff2(aliases::nil);
// use aliases::nil;
stuff3(Ok(()), Some(()), ()); // stuff3(Ok(nil), Some(nil), nil);
} |
@nrc Speculative discussion is generally unproductive, but in this case I argue that we can't escape speculation and that reserving is the right speculation. Speculation is unavoidable. Either the feature must speculate for a future edition, or an edition must to speculate for the syntax. Right now is we have good opportunity to discuss the second option. Not reserving inhibits discussion. It is reasonable to plan for Reserving costs almost nothing. This is not the same as keyword reservation, reserving a keyword has a serious impact on the availability of identifiers. The syntax discussed here is currently virtually useless and unused, the impact is likely to be zero. The alternative of stable feature gates makes little sense for changes of virtually zero breakage. So yes, let's speculate, and in that, let's reserve. Thanks @kennytm for writing this. |
It seems to me that all three points could apply just as well to keyword reservations, @leodasvacas, which makes me skeptical that there's a major difference here. The post in the other thread says
That's explicitly about avoiding speculation, regardless of kind. For named arguments, is it reasonable to have concerns about whether another mechanism is really needed in the language? Yes. Are there multiple possible reasonable syntaxes? Yes. (The RFC even mentions some.) Could it be done with a suboptimal transitional syntax in the epoch in which it's accepted, reserving the chosen one only in a following epoch? Yes. |
New keywords can be introduced as contextual keywords without involving editions (and optionally promoted to a full keyword in a later edition), because they mostly occur in syntactical positions where an extra identifier wouldn't be valid syntax anyway. When handling new keywords this way, we don't need to speculate (we can just implement the contextual keyword when the feature is designed) and there's nothing "inhibiting discussion" if it hasn't been reserved up-front. There's no comparable way to opportunistically reinterpret |
@scottmcm True, the policy as written does apply here. I'm just noting that some trade-offs are different.
Edit: The idea below could never work, nevermind. We can't reinterpret
|
I like @scottmcm do not see any notable difference between this RFC and #2441. If that one is closed then so should this one be in my opinion.
Well, @leodasvacas
This applies equally to
As explained in #2441, those reservations cost very little as well. The impact was not at all serious. |
Can anyone think of a real-world disadvantage to reserving this? Can you find any crate that uses code like this, even if it's accidental and leads to bugs? Any reason someone would write code like this, or a macro would generate it? I'm trying to think even of a reason you would use it for code golf, but it's generally not helpful to pass an empty tuple to a function. Really, the main reason someone would write something like this is to test if Rust supports named arguments. As far as advantages, it seems fairly clear that this is helpful if named arguments are added, and this syntax is used. And it does seem like the most obvious syntax. So though I don't have strong opinions on named arguments and like that Rust avoids breakings changes and tries not to arbitrarily limit what code can compile, the advantages of reserving the syntax seem to outweigh the philosophical disadvantages.
|
It introduces an unusual corner case, and that corner case only makes sense if supporting named arguments with this particular syntax. |
This is the the weird corner case as I understand it: foo(a = 5); is not the same as: foo((a = 5)); even though the second snippet only seems to have a redundant pair of parentheses added to it. You'd expect both of them to be equivalent to: let x = (a = 5);
foo(x); |
Hm, I hadn't followed that discussion. However, The other way to make it contextual would be to involve name resolution information (it's a call if there's a function |
Ouch! This hadn't even occurred to me; it seems more serious.
Agreed :) |
We could look for ways to make this prettier: foo(Foo {x: 5, y: 7}) How about this? foo({x: 5, y: 7}) Or this? foo{x: 5, y: 7} |
@repax I scribbled some thoughts about |
Not to me. The struct initialization and pattern binding syntax is unfortunately |
My previous workaround idea could never work, but one that could work is to have |
We discussed this a bit in the lang team meeting. Rough summary of that discussion:
Based on that: @rfcbot fcp close |
Team member @joshtriplett has proposed to close this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
I think a clippy lint is sufficient. For All that makes it highly unlikely to be unintentional. If anything, it's bad style. I think it's in the domain of clippy to lint against syntactically correct, intentional but weird expressions. |
@repax A function accepting a generic and resolving it to |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
I would like to share my disagreement with closing this RFC. I do agree that this RFC is similar enough to the ones that reserve keywords, that the same reasoning that @aturon articulated applies here as well However, I feel that (for the moment) there's a big flaw in the argument he made on the throw/fail RFC (#2441 (comment)). He states:
To me it seems that this argument contradicts itself. It's very easy to turn the reasoning around this way: Once this proposal from @aturon is actually an accepted RFC I completely agree that we can close all these issues about syntax and keyword reservations. Right now this is (afaik) not the case. To me it would be a shame to not have this syntax available until the next Rust edition, because no solution to adding keywords and syntax changes inbetween rust editions was accepted. So to me there's two solutions (which I'm both fine):
P.S. It would have been better if I would have brought this up in the previous RFC, where the original argument was made. However, I don't really follow the language design closely, but my eye was caught on this by a comment on reddit on the "This Week In Rust". I do hope this concern is still taken seriously though. PPS. Is there some way that I should let rfcbot know about this concern or is commenting like this enough. |
@JelteF The argument we're making is "this doesn't need to be tied to the edition". Given a concrete proposal we wanted to accept that uses this syntax for keyword arguments, we could make that transition with an explicit opt-in even without an edition, and then just get to a point where a future edition does it by default. So this wouldn't need to wait for a future edition, and doesn't need to preemptively reserve the syntax. |
Like I said, I would agree with the argument that you're making. IF there would be an actual accepted RFC for the process of adding these changes outside of an edition. As far as I can tell there is none. So using that as part of your reasoning against this RFC is at the moment just as weak an argument as using a possible future "keyword argument RFC" as an argument in favor of this RFC. |
The final comment period, with a disposition to close, as per the review above, is now complete. By the power vested in me by Rust, I hereby close this RFC. |
Should this really be closed when there has been no response regarding the concern I posted? |
@JelteF Ugh yeah, that's the pitfall of automatic closure by the bot. Sorry I didn't have a chance to reply sooner. I understand the argument you're making, but it also supposes that the RFCs are equivalent, in terms of consensus needed etc. The language team has talked extensively about keyword reservation at this point, and while they don't have agreement about the features that may need new keywords, they do have agreement about the need for a mechanism to introduce new keywords within an Edition. That doesn't make it a sure bet, of course, but as I summarized on the other thread, it has proved untenable to try to bikeshed keyword selection for features we haven't even agreed should exist. |
Thanks for the response. I guess that makes sense. I at least definitely agree that it would be super nice to have a mechanism for creating new keywords and breaking language changes in between editions. However, I do think it would be good not to wait too long with that RFC though. Because any RFCs that needs a new keyword would be blocked on it. |
Indeed, that's a great point! Probably we should wait until after the Edition ships before opening the discussion, but should do it ASAP after that. |