-
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
Undisambiguated generic arguments in expressions #2527
Conversation
What about statements like this? let a = (b<c, d>(e)); This can either mean a tuple let a = ((b < c), (d > e)); Or a pair of generic arguments. let a = b::<c, d>(e); |
@xfix: it seems we had overlooked that ambiguity before, thanks for pointing it out. This looks pretty difficult to resolve to me, so I'm going to close the RFC unless someone has a resolution. It was a nice idea while it lasted 🙁 |
This was a sad day! 😭 |
I've opened rust-lang/rust#53562 to ensure that any such attempt to unroot the Turbofish in the future shall have an earlier warning than we did. |
Additionally, at least for me personally, turbofish is less ambiguous for mentally parsing code as well, so I’ve never minded the slightly more verbose syntax. I also really don’t like this recent trend of oversimplification in Rust just to save a few characters... |
@novacrazy: I think you'll find that there's always been a trend of reducing characters in Rust (take a look at all the keywords) 😉 |
@varkor Have you considered allowing only |
@eddyb I feel like allowing it in the special case of zero or one type parameters is going to cause confusion and make the grammar that much more irregular. |
I'm actually with @novacrazy on this: I think the Rust syntax is superior to the C++ syntax. Angle brackets are pretty common; disambiguation is helpful. |
This is really unfortunate, but I'd still really like a unification of providing generic arguments. The simplest way I see would just be to require turbofish everywhere, but this is quite ugly. |
I like the approach Kotlin takes on the disambiguation -- in case it's not obvious how to parse an expression, Kotlin will ask to put parens. No turbofish and no additional parens 99% of the time. |
Hmm… interesting. Kotlin doesn't have tuples (or a comma operator like C++), but you can get a similar effect with function calls:
This appears to always be parsed as a generic, not a pair of comparisons – see this test program. I suppose that if you did want two comparisons, you could add parentheses:
The approach Kotlin uses seems to require infinite lookahead. When encountering a
…these are all legal ways for the line to end:
(To play with this, look at That leaves me with a few questions:
|
The advantage of |
…nagisa Lament the invincibility of the Turbofish Here a test case is added to ensure that any others attempting to drive the Turbofish to extinction have second thoughts. Previously the [entire test suite would succeed](rust-lang#53511) if generic arguments were accepted without disambiguation, making for [confusing and heartbreaking circumstances](rust-lang/rfcs#2527).
I'm betting on 2021 :) |
For me |
@artemshein I think that makes some sense, though. |
@BatmanAoD haha, ok, maybe, but it's still ugly and doesn't reflect the generic parameters definition syntax ( |
@artemshein The "ugliness" is of course a matter of personal aesthetic preference. Personally, coming from C++, when I saw the turbofish I immediately thought "oh, great, that's an improvement!" I realize I am in the minority in this view, though. If consistency is the goal, I would personally rather see definition syntax match expression context, i.e. I also wouldn't call it an "unnecessary thing to learn." Clearly, per this discussion, it is necessary for Rust, even if it's different from C++! |
Yeah I think just using turbofish everywhere might be superior. One idea I also had was since people dislike writing |
@laaas I had the |
…nagisa Lament the invincibility of the Turbofish Here a test case is added to ensure that any others attempting to drive the Turbofish to extinction have second thoughts. Previously the [entire test suite would succeed](rust-lang#53511) if generic arguments were accepted without disambiguation, making for [confusing and heartbreaking circumstances](rust-lang/rfcs#2527).
I assumed that they are banned now so they can be allowed in the future in their intuitive meaning -
All these cases exist purely for diagnostics and can be removed without affecting Rust grammar. This feature also directly interferes with const generic parameters. |
That was one of the motivations, but note that chained comparisons in the same direction (e.g. @petrochenkov:
Expressions that are const generic arguments must be enclosed within a block, therefore no additional ambiguity over the tuple case given above is created. |
Yes, if
Text and examples in that RFC contradict to itself, the precise rules were written out somewhere in the discussion thread, but were never moved into the RFC text properly. |
Well, However, …that is, under the parsing rule for const parameters that you describe. But it’s worth noting that const generics are not stable (or even fully implemented) yet, so it would be possible to change the rule back to what’s described in the RFC. It’s certainly nice to minimize the need for braces in const parameters, but on the other hand, “expressions that start with literals but reference variables later on” seems like a relatively narrow category. |
...that said, if Since it’s rather unlikely that |
…nagisa Lament the invincibility of the Turbofish Here a test case is added to ensure that any others attempting to drive the Turbofish to extinction have second thoughts. Previously the [entire test suite would succeed](rust-lang#53511) if generic arguments were accepted without disambiguation, making for [confusing and heartbreaking circumstances](rust-lang/rfcs#2527).
@varkor If you look at all 3 possible branches after that, the parser will always emit an error, either the original error or the specific error suggesting to use parenthesis around the expression. That code path could be removed and the compiler would start accepting that code as valid (which is what rust-lang/rust#42578 originally did), but the agreement was reached that it was a bad idea to change the grammar in that way. I would love it if with the code you wrote in rust-lang/rust#53578, we could add the same kind of suggestions for people that may not have the full grasp of how to use the turbofish yet. We would not be fixing the ergonomics issue, but we'd be fixing part of the discoverability problem. |
At the risk of moving the anger from one fanaticism to another, may I suggest that < be considered to mean "less than" only if it is surrounded by whitespace on both sides? And likewise that < be considered to be generic-oriented only if it is NOT surrounded by whitespace on both sides? Then this |
This was discussed on Zulip at one point. I thought this could be a reasonable design decision under the circumstances, but there are those (including on the lang team) who don't agree, so I don't think this changes the impasse. |
Make disambiguating generic arguments in expressions with
::
optional, allowing generic arguments to be specified without::
(making the "turbofish" notation no longer necessary).Rendered
This makes the following valid syntax:
Thanks to @Centril, @scottmcm, @joshtriplett and @rpjohnst for feedback!