Skip to content
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

tracking issue for ? macro repetition #48075

Closed
6 tasks done
nikomatsakis opened this issue Feb 8, 2018 · 94 comments
Closed
6 tasks done

tracking issue for ? macro repetition #48075

nikomatsakis opened this issue Feb 8, 2018 · 94 comments
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Feb 8, 2018

RFC: rust-lang/rfcs#2298

Status

Known bugs

None.

Unresolved questions to be answered before stabilization

  • Should the ? Kleene operator accept a separator? Adding a separator is completely meaningless (since we don't accept trailing separators, and ? can accept "at most one" repetition), but allowing it is consistent with + and *. Currently, we allow a separator. We could also make it an error or lint.
@nikomatsakis nikomatsakis added T-lang Relevant to the language team, which will review and decide on the PR/issue. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. labels Feb 8, 2018
@nikomatsakis
Copy link
Contributor Author

cc @mark-i-m

@mark-i-m
Copy link
Member

@nikomatsakis Could you update the checklist? The preliminary impl is available on nightly.

@mark-i-m
Copy link
Member

@Centril I think you need to update the tracking issue in the RFC, too 😛

@Centril
Copy link
Contributor

Centril commented Feb 27, 2018

@mark-i-m Already done 🤣

@clarfonthey
Copy link
Contributor

Is there any plan to stabilise this soon?

@mark-i-m
Copy link
Member

I think it depends on experience if this is the right way to solve the problems involved... Frankly, I haven't really written any macros since I implemented this 😛 ...

I think there is still the one problem that was pointed out in the RFC thread: this doesn't provide a clean solution for trailing commas in * macros, since you would end up accepting foo!{,} which is a bit weird.

We could conceivably stabilize this anyway if people find it really useful. Any thoughts?

@clarfonthey
Copy link
Contributor

I personally see it more ergonomic to have rules for () and $(...),+ $(,)? than $(...),* and $(...,)*, as the former usually requires way less duplication than the latter. The former it also natural for recursive macros, and it basically solves the trailing comma problem nicely.

Considering how it also allows optional arguments as well, I think it's pretty much a win here.

@clarfonthey
Copy link
Contributor

As far as the one unresolved question (following separators) goes, I'm in favour of allowing it for the sake of a simpler grammar, but linting it in rustc (not clippy). That seems pretty ergonomic to me, and the compiler internally would have to accept it with a separator anyways to provide useful error messages.

@alexreg
Copy link
Contributor

alexreg commented Apr 5, 2018

I don’t see the point of allowing the trailing separator even with a lint. It’s totally meaningless as you point out, so its existence in code would probably just perplex readers!

@mark-i-m
Copy link
Member

mark-i-m commented Apr 5, 2018

the compiler internally would have to accept it with a separator anyways to provide useful error messages.

Hmm... I guess this is a good point. It means that probably the code complexity (in the compiler) of keeping or not keeping the separator is about the same. Still, having a simpler grammar is nice, especially if libsyntax2.0 ever actually intends have something auto-generated.

What about a deny-by-default lint?

@durka
Copy link
Contributor

durka commented Apr 5, 2018

When would anyone ever allow the lint, though? This kinda sounds like "we can't decide, just make it configurable".

@mark-i-m
Copy link
Member

mark-i-m commented Apr 5, 2018

When would anyone ever allow the lint, though?

My guess: probably never. On the other hand, when is anyone likely to actually use a separator for a single item? Will anyone ever run into the lint? The tradeoff is between a mildly simpler grammar and mildly simpler UX.

@mark-i-m
Copy link
Member

mark-i-m commented Apr 5, 2018

The changes if we want disallow it are pretty minimal:

diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index f324ede..a6fb782 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -470,8 +470,11 @@ where
                         GateIssue::Language,
                         explain,
                     );
+                } else {
+                    sess.span_diagnostic
+                        .span_err(span, "`?` macro repetition does not allow a separator");
                 }
-                return (Some(tok), op);
+                return (None, op);
             }
             Ok(Ok(op)) => return (Some(tok), op),

@alexreg
Copy link
Contributor

alexreg commented Apr 5, 2018

My guess: probably never. On the other hand, when is anyone likely to actually use a separator for a single item? Will anyone ever run into the lint? The tradeoff is between a mildly simpler grammar and mildly simpler UX.

I think this is really "designer's/developer's motivation" vs. "user's motivation". And making the user happy should always win, I think. After all, there's a fair bit of ugly stuff in most compilers (including the Rust one), but most people don't care about it, because they don't touch it, and if they do they expect a significant learning curve. A compiler's end goal is to support a language rather than have an elegant internal structure (which is more of a bonus). The fact is, if you want to go messing with the compiler or libsyntax, taking the time to learn the slight difference between ? and */+ is no big deal. If you're a user, especially one new to Rust, that could be a real gotcha.

Now, since from the Rust user's perspective this feature adds literally nothing, and adding an error (as @mark-i-m's diff shows) is very straightforward, I maintain we disallow it. @durka's point and the article he links to is also a good one. Configuration is only a good thing when it's absolutely needed. Convention over it any other time.

@mark-i-m
Copy link
Member

mark-i-m commented Apr 5, 2018

I went back and re-read part of the RFC thread, and this comment stuck out to me: rust-lang/rfcs#2298 (comment)

There is the question of what this matches: $(a)?+. It could be:

  • a+ (hypothetical)
  • a?a?a (current implementation)

Allowing the separator actually allows us to disambiguate:

  • $(a),?+ matches a+
  • $(a)?+ matches a?a?a

But at the same time, this seems really dubious, since removing the separator seems like it should not change the pattern matched. If we disallow separator on ?, then things are a bit cleaner:

  • $(a),?+ is parsing error
  • $(a)?+ matches a?a?a

Admittedly, this is all a bit contrived, but it does seem to throw the balance in favor of disallowing a separator on ?...

EDIT: corrected typo

@durka
Copy link
Contributor

durka commented Apr 5, 2018

Agreed that if removing the separator changes things that seems weird and bad. But it's a shame that in the latter scenario you can't match aa+...

@mark-i-m
Copy link
Member

mark-i-m commented Apr 5, 2018

One option would be to change the disambiguation strategy. That is, we stop allowing ? as a separator for any of the Kleene operators. This would be a breaking change, but perhaps it might not be that bad?

@durka
Copy link
Contributor

durka commented Apr 5, 2018 via email

@alexreg
Copy link
Contributor

alexreg commented Apr 5, 2018

Now that you mention that, maybe a two-character ?? operator makes the most sense. No ambiguity, no allowance for specification of meaningless separators, and no prevention of using ? as a separator for the other Kleene operators.

@mark-i-m
Copy link
Member

Stabilization Report 🎉

(Let me know if I missed anything)

Description of behavior

  • Edition 2015 ? is a macro separator, not a kleene op, but using it as a separator triggers a migration lint.

    • This represents no change from previous behavior except the migration lint.
  • Edition 2018 ? is not a valid separator. ? is a valid Kleene op.

    • Add a Kleene operator to macros to repeat a pattern at most once: $(pat)?. Here, ? behaves like + or * but represents at most one repetition of pat.
    • The ? Kleene operator does not accept any separator token, unlike + and *. For example, $(a),? is an error. This is because we don't allow trailing separators, so any separator used with the ? Kleene operator would be impossible to use.
    • For example, under this proposal, $(a)?+ matches + and a+ unambiguously.
  • For a longer description of alternatives and behavior, see this FCP.

  • Note, that the stabilization only impacts Edition 2018.

Differences from RFC

Link to RFC

  • The RFC proposed a disambiguation strategy that used lookahead to discern whether a ? token was a separator for + or * OR was a ? Kleene op. We opted instead to remove ? as a separator in Edition 2018 as a breaking change, removing the ambiguity altogether.

  • The RFC proposed making a minor breaking change in Edition 2015 to change the disambiguation as mentioned above. Instead, we opted to only enable ? Kleene operator in Edition 2018. That is, Edition 2015 is unchanged (except for a migration lint), whereas Edition 2018 has the changes described above.

  • The RFC had an unresolved question: "Should the ? Kleene operator accept a separator token?". We decided the answer is "no".

Documentation and Testing

@mark-i-m
Copy link
Member

@nikomatsakis @Centril done :) Let me know if I missed anything

@mark-i-m
Copy link
Member

Also, it looks like the checklist in the OP should be updated.

@Centril
Copy link
Contributor

Centril commented Oct 26, 2018

@rfcbot resolve report-and-tests

@mark-i-m that's a most excellent report. :)

@alexreg
Copy link
Contributor

alexreg commented Oct 26, 2018

Well done on the super-meticulous work @mark-i-m. Glad we can finally get this feature stabilised!

@rfcbot
Copy link

rfcbot commented Nov 20, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Nov 20, 2018
@Centril
Copy link
Contributor

Centril commented Nov 23, 2018

@mark-i-m Since you did the implementation work, could you prepare a PR for the stabilization as well? :)

@mark-i-m
Copy link
Member

Sure, but it might be a few days before I can get to it

@Centril
Copy link
Contributor

Centril commented Nov 23, 2018

@mark-i-m Ah; there's no great rush; 1.32 goes into beta on the 7th. Do you think you can get it landed by then?

@mark-i-m
Copy link
Member

Yeah, I think I could do it by the end of the week.

pietroalbini added a commit to pietroalbini/rust that referenced this issue Nov 28, 2018
…lexcrichton

Stabilize feature `macro_at_most_once_rep`

a.k.a. `?` Kleene operator 🎉

cc rust-lang#48075

r? @Centril
bors added a commit that referenced this issue Nov 29, 2018
Stabilize feature `macro_at_most_once_rep`

a.k.a. `?` Kleene operator 🎉

cc #48075

r? @Centril
@mark-i-m
Copy link
Member

#56245 has merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests