Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upRFC: `?` repetition in macro rules #2298
Conversation
Centril
added
the
T-lang
label
Jan 17, 2018
mark-i-m
changed the title
Add RFC: macro-at-most-once-rep
RFC: `?` repetition in macro rules
Jan 17, 2018
Centril
reviewed
Jan 17, 2018
|
Great idea in general and I would love to have this in the language. I have some minor stylistic suggestions tho (I hope you don't mind those..) as well as an improvement idea for the Motivation-section. |
| Summary | ||
| ------- | ||
|
|
||
| Add a repetition specifiers to macros to repeat a pattern at most once: `$(pat)?`. `?` behaves like `+` or `*` but represents at most one repetition of `pat`. |
This comment has been minimized.
This comment has been minimized.
| Motivation | ||
| ---------- | ||
|
|
||
| There are two specific use cases in mind: |
This comment has been minimized.
This comment has been minimized.
Centril
Jan 17, 2018
Contributor
Stylistic suggestion:
- Break into two
##headings for increased readability.
| } | ||
| ``` | ||
|
|
||
| 2. Trailing commas. It's kind of infuriating that the best way to make a rule tolerate trailing commas TMK is to create another identical rule that has a comma at the end: |
This comment has been minimized.
This comment has been minimized.
Centril
Jan 17, 2018
Contributor
Stylistic suggestions:
It's kind of infuriatingfeels a bit strong and subjective- Expand
TMK=> to my knowledge. (even better: remove it all together).
| } | ||
| ``` | ||
|
|
||
| The pattern portion is composed of zero or more subpatterns concatenated together. One possible subpattern is to repeat another subpattern some number of times. This is extremely useful when writing variadic macros (e.g. `println`): |
This comment has been minimized.
This comment has been minimized.
| Reference-level explanation | ||
| --------------------------- | ||
|
|
||
| `?` is identical to `+` and `*` in use except that it represents "at most once" repetition. The implementation ought to be very similar to them. IIUC only the parser needs to change. I don't think it would be technically difficult to implement, nor do I think it would add much complexity to the compiler. |
This comment has been minimized.
This comment has been minimized.
Centril
Jan 17, 2018
Contributor
Stylistic suggestions:
- depersonalize IIUC (and expand)
- depersonalize
I don't think
I don't think it would be technically difficult to implement, nor do I think it would add much complexity to the compiler.
This is more apt in the rationale/drawbacks sections.
The reference (AFAIK, for lang RFCs) should be more a language specification and technical description that can be pasted into the actual reference without many changes.
|
|
||
| Motivation | ||
| ---------- | ||
|
|
This comment has been minimized.
This comment has been minimized.
Centril
Jan 17, 2018
Contributor
Another motivation you could add is an argument from familiarity with regular expressions.
This comment has been minimized.
This comment has been minimized.
mark-i-m
Jan 17, 2018
Author
Contributor
I mention this in the rationale as a reason why ? was chosen, but since the RFC explicitly chooses to not add {M, N}, I think it would be hard to add familiarity with regexes to the motivation.
This comment has been minimized.
This comment has been minimized.
17cupsofcoffee
commented
Jan 17, 2018
•
|
I think this is a great idea - the trailing commas thing in particular has always irritated me, given that rustfmt favours them using them for structs/enums/etc. I do wonder if using |
This comment has been minimized.
This comment has been minimized.
|
@Centril Thanks for the comments! I tried to address them in the latest commit. Specifically:
|
This comment has been minimized.
This comment has been minimized.
I thought about this a bit too. However, the use of |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
17cupsofcoffee
commented
Jan 18, 2018
•
|
@Ixrec Yeah, it's not a huge issue ("if a |
kennytm
reviewed
Jan 18, 2018
| --------- | ||
| While there are grammar ambiguities, they can be easily fixed, as noted by @kennytm [here](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/2?u=mark-i-m): | ||
|
|
||
| > There is ambiguity: $($x:ident)?+ today matches a?b?c and not a+. Fortunately this is easy to resolve: you just look one more token ahead and always treat ?* and ?+ to mean separate by the question mark token. |
This comment has been minimized.
This comment has been minimized.
kennytm
Jan 18, 2018
Member
This should better be put back to reference-level explanation. You cannot implement ? without clarifying this bit.
This comment has been minimized.
This comment has been minimized.
|
@kennytm I moved the note on ambiguity back to the reference section, but left a note in drawbacks. |
This comment has been minimized.
This comment has been minimized.
Apanatshka
commented
Jan 19, 2018
|
I'd just like to mention, since this didn't come up yet, that besides |
This comment has been minimized.
This comment has been minimized.
|
@Apanatshka You can build "two or more" with |
This comment has been minimized.
This comment has been minimized.
|
Also, I think |
mark-i-m
referenced this pull request
Jan 19, 2018
Merged
Run rustfmt and add doc comments to libsyntax/ext/tt/quoted.rs #47603
This comment has been minimized.
This comment has been minimized.
|
Is there any way to request an FCP for this? It's not a very big feature and seems to have wide support. I don't want it to be forgotten... |
This comment has been minimized.
This comment has been minimized.
gbutler69
commented
Jan 24, 2018
|
@mark-i-m '''@Apanatshka You can build "two or more" with pat1 pat2 $(more)*, but I don't think you can build it with {m,n}.''' Generalized {m,n} would allow:
If you followed the same rules as for Regex. |
This comment has been minimized.
This comment has been minimized.
|
@rfcbot fcp merge Is there an ambiguity like That said, I bang my head against this all the time. I think that having We should address who will implement it (or mentor an implementation of it). |
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Jan 25, 2018
•
|
Team member @nikomatsakis has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, 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. |
rfcbot
added
the
proposed-final-comment-period
label
Jan 25, 2018
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis You typed Yes there is ambiguity, but it is already acknowledged in the RFC with a way to workaround it, so it is not a problem. |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis I have already started implementing: rust-lang/rust@master...mark-i-m:at-most-once-rep |
This comment has been minimized.
This comment has been minimized.
|
Also, it would be nice (though not necessary) if rust-lang/rust#47732 and rust-lang/rust#47603 were merged before the implementation of this feature (purely for code cleanliness)... |
This comment has been minimized.
This comment has been minimized.
|
Also, cc @ExpHP, who I believe, went around adding trailing comma support to a bunch of macros in |
This comment has been minimized.
This comment has been minimized.
ExpHP
commented
Jan 26, 2018
•
|
Ah, I forgot about that! I enumerated all the places they're missing but haven't actually fixed them yet. I'm glad to see this is already on the track to acceptance. I'd think I'd be hard pressed to find somebody who has written macros and hasn't wanted something like this from day one. |
This comment has been minimized.
This comment has been minimized.
|
I'm somewhat reluctant to extend the macro pattern language before we decide if and how the pattern language should change for macros 2.0. But, I guess it is nice to experiment with it since we don't have any firm plans, and I assume this could be left unstable for some time. |
This comment has been minimized.
This comment has been minimized.
|
@nrc Could you be a bit more specific about your concerns? For example, do you feel that adding this will complicate macros 2.0 somehow? |
This comment has been minimized.
This comment has been minimized.
|
Made a tracking issue since we plan to land the implementation before FCP is complete: |
This comment has been minimized.
This comment has been minimized.
|
So the breaking change proposal would also not accept a separator with
`$(pat)?`, right?
…On Thu, Feb 8, 2018 at 1:08 PM, Niko Matsakis ***@***.***> wrote:
Made a tracking issue since we plan to land the implementation before FCP
is complete:
rust-lang/rust#48075 <rust-lang/rust#48075>
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2298 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAC3n6wncWx60qFnMSNfbYXOPj5c1hzcks5tSzgogaJpZM4RhtUf>
.
|
This comment has been minimized.
This comment has been minimized.
|
I'm just not sure this rises to the level of breaking changes. It's not a
high-priority bug fix or anything. Yeah it's a feature that should've been
included from the beginning, but we shouldn't set the precedent of doing
breaking changes like that whenever we think they can fly under the radar.
…On Thu, Feb 8, 2018 at 1:15 PM, Alex Burka ***@***.***> wrote:
So the breaking change proposal would also not accept a separator with
`$(pat)?`, right?
On Thu, Feb 8, 2018 at 1:08 PM, Niko Matsakis ***@***.***>
wrote:
> Made a tracking issue since we plan to land the implementation before FCP
> is complete:
>
> rust-lang/rust#48075 <rust-lang/rust#48075>
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <#2298 (comment)>, or mute
> the thread
> <https://github.com/notifications/unsubscribe-auth/AAC3n6wncWx60qFnMSNfbYXOPj5c1hzcks5tSzgogaJpZM4RhtUf>
> .
>
|
This comment has been minimized.
This comment has been minimized.
I think that's orthogonal. The breaking change would be to remove ? as a separator. That would have the benefit of ? being exactly the same as + and *, but...
I tend to agree. The current implementation is not a breaking change. |
dtolnay
reviewed
Feb 10, 2018
|
|
||
| ```rust | ||
| macro_rules! foo { | ||
| ($(pat),*,) => { foo!( $(pat),* ) }; |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
|
||
| ```rust | ||
| macro_rules! foo { | ||
| ($(pat),* $(,)?) => { |
This comment has been minimized.
This comment has been minimized.
dtolnay
Feb 10, 2018
Member
It sounds like better support for trailing delimiters is a major part of the motivation for this RFC and why people are excited about it. But the old approach shown under "Currently" still seems better than the one here because with ? we cannot disallow an invocation consisting of only a comma, foo!(,). Is the idea that $(,)? would be a quick and easy shorthand but macro authors would continue to use the old approach if they want their macro to be maximally correct? If so, could you brainstorm some ideas for how optional trailing delimiters could be better supported?
This comment has been minimized.
This comment has been minimized.
durka
Feb 10, 2018
Contributor
One way would be a new repetition operator, let's say $(pat),# (# obviously up for
This comment has been minimized.
This comment has been minimized.
mark-i-m
Feb 11, 2018
Author
Contributor
Hmm... that's true. It works well if you have + repetition.
One option is to combine ? with | as described in #2298 (comment)
This comment has been minimized.
This comment has been minimized.
mark-i-m
Feb 11, 2018
Author
Contributor
Another option is to create another repetition mode which indicates trailing commas: $[pat],*
dtolnay
reviewed
Feb 10, 2018
|
|
||
| There are two specific use cases in mind. | ||
|
|
||
| ## Macro rules with optional parts |
This comment has been minimized.
This comment has been minimized.
dtolnay
Feb 10, 2018
Member
Could you point out some macros from crates.io that would benefit from this syntax for optional parts? The example given here strikes me as contrived.
This comment has been minimized.
This comment has been minimized.
durka
Feb 10, 2018
•
Contributor
I would have used it in this crate to match the following syntaxes in one rule:
trait Foo { ... }trait Foo: Bar { ... }pub trait Foo { ... }pub trait Foo: Bar { ... }
namely the rule:
($vis:vis trait $traitname:ident $(: $supertrait:ident)? { $($body:tt)* })(edited to fix local ambiguity)
This comment has been minimized.
This comment has been minimized.
mark-i-m
Feb 11, 2018
Author
Contributor
This also strikes me as a candidate for reimplementation: https://docs.rs/clap/2.29.4/clap/macro.clap_app.html
This comment has been minimized.
This comment has been minimized.
ExpHP
commented
Feb 10, 2018
•
|
One thing I don't see discussed is that this enables some things to be written with a single rule that used to require extra layers of indirection or even incremental TT munchers. For instance, any example where macro_rules! my_match {
(($expr:expr) {
$( $pat:pat $(if $guard:expr)? => $block:block $(,)? )+
}) => {
match $expr { $( $pat $(if $guard)? => $block )+ }
};
}
fn main() {
my_match!{ (Some(3)) {
Some(n) if n % 2 == 0 => { println!("even"); }
Some(5) => { println!("five"); },
_ => {}
}}
}(Though it still cannot handle all cases unless we had some sort of "alternative operator", like |
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Feb 10, 2018
|
The final comment period is now complete. |
bors
added a commit
to rust-lang/rust
that referenced
this pull request
Feb 11, 2018
This comment has been minimized.
This comment has been minimized.
That seems like a much more significant addition, though, and it would require bigger changes to the macro parser. |
bors
added a commit
to rust-lang/rust
that referenced
this pull request
Feb 11, 2018
This comment has been minimized.
This comment has been minimized.
|
Ok, I added a bit to the drawbacks section to mention @dtolnay's comments in #2298 (review). For now, I think this is still a reasonable step, and we will get more insight by playing around with the preliminary implementation. |
This comment has been minimized.
This comment has been minimized.
ExpHP
commented
Feb 11, 2018
•
Indeed. I also feel that alternatives carry a cognitive and maintenance burden for macro authors which does not scale well with the size of the problem being solved, and I did not intend to suggest it as a viable alternative. (pun not intended) (in particular, the fact that a macro must ultimately produce an expr, type, or items means that users would be forced to put many orthogonal and/or nested groups of alternatives into a single pattern) |
This comment has been minimized.
This comment has been minimized.
ExpHP
commented
Feb 11, 2018
Musing a bit further, this reasoning could be applied to many proposals for new It seems that, given the unavoidable limitations of That is to say, I think the ability to parse everything is very distinctly a non-goal. |
This comment has been minimized.
This comment has been minimized.
I disagree. We should make the macro parser Turing complete. ( |
This comment has been minimized.
This comment has been minimized.
|
Oh, it is. But I philosophically disagree on a different level -- more general features create more power than cognitive burden. |
This comment has been minimized.
This comment has been minimized.
|
It looks like discussion has died down... |
This comment has been minimized.
This comment has been minimized.
|
Perhaps this can be merged now? |
Centril
referenced this pull request
Feb 27, 2018
Closed
Tracking issue for RFC 2298, `?` repetition in macro rules #48591
Centril
merged commit c40b98a
into
rust-lang:master
Feb 27, 2018
This comment has been minimized.
This comment has been minimized.
|
Huzzah! The RFC is merged! Tracking issue: rust-lang/rust#48075 |
This comment has been minimized.
This comment has been minimized.
|
Thanks @Centril I think rust-lang/rust#48075 is already a tracking issue. |
This comment has been minimized.
This comment has been minimized.
|
Request for comments/FCP on newest implementation: rust-lang/rust#51934 |
mark-i-m commentedJan 17, 2018
•
edited by Centril
Rendered
Discussion
EDIT: Implementation in rust-lang/rust#47752
Tracking issue: rust-lang/rust#48075