# Pre-RFC: at most one repetition macro patterns

**URL:** <https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557>\
**Category:** language design\
**Created:** [January 15, 2018, 5:44am UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557 "2018-01-15T05:44:55Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [January 15, 2018, 5:44am UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/1 "2018-01-15T05:44:55Z")

</div>

_EDIT_: updated alternatives

_EDIT 2_: more updates to alternatives, especially `{m,n}`, and add @kennytm's comment on ambiguity

* * *

_EDIT 3_: FYI: This is being stabilized 🎉

See the stabilization report here: [https://github.com/rust-lang/rust/issues/48075#issuecomment-433243048](https://github.com/rust-lang/rust/issues/48075#issuecomment-433243048)

Many thanks to all who helped out along the way! It's been quite a journey since January 14!

* * *

## 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`.

## Motivation

There are two specific use cases in mind:

1. Any macro rule with optional parts. Currently, you just have to write two rules and possibly have one "desugar" to the other.

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:

## Guide-level explanation

In Rust macros, you specify some "rules" which define how the macro is used and what it transforms to. For each rule, there is a pattern and a body:

```rust
macro_rules! foo {
  (pattern) => { body }
}

```

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`):

```rust
macro_rules! println {
  // Takes a variable number of arguments after the template
  ($tempate:expr, $($args:expr),*) => { ... }
}

```

which can be invoked like so:

```rust
println!("") // 0 args
println!("", foo) // 1 args
println!("", foo, bar) // 2 args
...

```

The `*` in the pattern of this example indicates "0 or more repetitions". One can also use `+` for "at _least_ one repetition" or `?` for "at _most_ one repetition".

In the body of a rule, one can specify to repeat some code for every occurence of the pattern in the invokation:

```rust
macro_rules! foo {
  ($($pat:expr),*) => {
    $(
      println!("{}", $pat)
    )* // Repeat for each `expr` passed to the macro
  }
}

```

The same can be done for `+` and `?`.

The `?` operator is particularly useful for making macro rules with optional components in the invocation or for making macros tolerate trailing commas.

## 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.

The `?` character is chosen because

- While there are grammar ambiguities, they can be easily fixed, as noted by @kennytm here:

- It is consistent with common regex syntax, as are `+` and `*`

- It intuitively expresses "this pattern is optional"

## Drawbacks

I can't really think of anything. Feel free to suggest.

## Rationale and Alternatives

One alternative to alleviate the trailing comma paper cut is to allow trailing commas automatically for any pattern repetitions. This would be a breaking change. Also, it would allow trailing commas in potentially unwanted places. For example:

```rust
macro_rules! foo {
  ($($pat:expr),*; $(foo),*) => {
    $(
      println!("{}", $pat)
    )* // Repeat for each `expr` passed to the macro
  }
}

```

would allow

```rust
foo! {
  x,; foo
}

```

Also, rather than have `?` be a repetition operator, we could have the compiler do a "copy/paste" of the rule and insert the optional pattern. Implementation-wise, this might reuse less code than the proposal. Also, it's probably less easy to teach; this RFC is very easy to teach because `?` is another operator like `+` or `*`.

We could use another symbol other than `?`, but it's not clear what other options might be better. `?` has the advantage of already being known in common regex syntax as "optional".

It has also been suggested to add `{M, N}` (at least `M` but no more than `N`) either in addition to or as an alternative to `?`. Like `?`, `{M, N}` is common regex syntax and has the same implementation difficulty level. However, it's not clear how useful such a pattern would be. In particular, we can't think of any other language to include this sort of "partially-variadic" argument list. It is also questionable why one would want to _syntactically_ repeat some piece of code between `M` and `N` times. Thus, this RFC does not propose to add `{M, N}` at this time (though we note that it is forward-compatible).

Finally, we could do nothing and wait for macros 2.0. However, it will be a while (possibly years) before that lands in stable rust. The current implementation and proposals are not very well-defined yet. Having something until that time would be nice to fix this paper cut. This proposal does not add a lot of complexity, but does nicely fill the gap.

## Unresolved Questions

None that I can think of...

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [January 15, 2018, 4:45pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/2 "2018-01-15T16:45:01Z")

</div>

> [@mark-i-m](#):
>
> Under this RFC, one would simply write:
> 
> ```rust
> macro_rules! foo {
> (do $b1:block $(and $b2:block)?) => {
> $b1
> $($b2)*
> }
> }
> 
> ```

Why is `$b2` expanded using `*`?

> [@mark-i-m](#):
>
> I don’t think it has grammar ambiguities

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.

> [@mark-i-m](#):
>
> Finally, we could consider adding something more general, such as “at most N repetitions”. It’s not clear what syntax we could use for this. Perhaps something like $(pat)N?, where N is replaced with an integer. I’m not sure if this retains syntactic disambiguity. Also, it’s not clear how useful such a pattern would be.

`$($x:tt){2,7}` 😉

---

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [January 15, 2018, 5:03pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/3 "2018-01-15T17:03:29Z")

</div>

@kennytm Thanks!

> [@kennytm](#):
>
> Why is $b2 expanded using \*?

TBH, I thought this was the standard way to expand the repetition... Is it not? The Book doesn't seem to say. I'm now guessing you are supposed to use `*`, `+`, or `?` -- which ever you used in the pattern?

> [@kennytm](#):
>
> 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.

Ah, I wasn't sure if this was allowed or not... Also not very well specified in the Book.

> [@kennytm](#):
>
> $($x:tt){2,7}

I still don't quite understand when this would be useful, though. Could you give an example use case?

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [January 15, 2018, 5:16pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/4 "2018-01-15T17:16:13Z")

</div>

Having `?` would be super useful precisely for the reasons you mention…

… However, do we want to improve macros by example at all?

Should we not wait for macros 2.0 and provide this there?

AFAIK `macro_rules!` will be deprecated eventually?

---

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [January 15, 2018, 5:57pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/5 "2018-01-15T17:57:34Z")

</div>

@Centril Macros 2.0 is moving a bit slowly, and all the documentation and drafts I can find are a vague and hand-wavy. I suspect it will be years before we get a stable macros 2.0, and in the meantime, this should be a workable, relatively simple fix for a paper cut.

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [January 15, 2018, 6:01pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/6 "2018-01-15T18:01:25Z")

</div>

> [@mark-i-m](#):
>
> TBH, I thought this was the standard way to expand the repetition… Is it not? The Book doesn’t seem to say. I’m now guessing you are supposed to use \*, +, or ? – which ever you used in the pattern?

Yes if it’s defined as `$(…)+` then you’re supposed to use `+` to expand it, though I’m not sure if the compiler will check this.

> [@mark-i-m](#):
>
> I still don’t quite understand when this would be useful, though. Could you give an example use case?

I don’t think it is useful, I just mean instead of `N?`, we could reuse the standard regex notation `{0,N}`.

---

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [January 15, 2018, 6:16pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/7 "2018-01-15T18:16:04Z")

</div>

> [@kennytm](#):
>
> I don’t think it is useful, I just mean instead of N?, we could reuse the standard regex notation {0,N}.

I guess it's a possibility... will add to the "alternatives" section

> [@Centril](#):
>
> Should we not wait for macros 2.0 and provide this there?

Also, will add this to alternatives

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [January 15, 2018, 7:30pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/8 "2018-01-15T19:30:14Z")

</div>

> [@mark-i-m](#):
>
> @Centril Macros 2.0 is moving a bit slowly, and all the documentation and drafts I can find are a vague and hand-wavy. I suspect it will be years before we get a stable macros 2.0, and in the meantime, this should be a workable, relatively simple fix for a paper cut.

This is all super true - I've never read an RFC as vague as the macros 2.0 one. I feel that after the fact, this should have been an eRFC.

So I buy completely your answer.

> [@mark-i-m](#):
>
> Also, will add this to alternatives

That's good. But given your answer, I wouldn't too much emphasis on the alternative.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [January 15, 2018, 7:31pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/9 "2018-01-15T19:31:51Z")

</div>

> [@kennytm](#):
>
> I don’t think it is useful, I just mean instead of N?, we could reuse the standard regex notation {0,N}.

Even if we had `{0, N}` notation, I still think `?` should be there. So I don't see them as complementary. The `?` qualifier on rules is so pervasive and common that it makes sense to have custom syntax for it.

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [January 16, 2018, 5:17am UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/10 "2018-01-16T05:17:46Z")

</div>

> [@Centril](#):
>
> Even if we had {0, N} notation, I still think ? should be there. So I don’t see them as complementary. The ? qualifier on rules is so pervasive and common that it makes sense to have custom syntax for it.

I don’t mean we replace `?` with `{0,1}`, I mean if we do want to support “repeat at most 8 times” then `{0,8}` should be better than `8?`. This means we cover all regex quantifiers: `*`, `+`, `?` and `{m,n}`.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [January 16, 2018, 5:29am UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/11 "2018-01-16T05:29:21Z")

</div>

Sure, that sounds all good to me =) But `{m, n}` may cause more breakage?

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [January 16, 2018, 5:41am UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/12 "2018-01-16T05:41:41Z")

</div>

`{m,n}` does not cause any breakage more than `?`, it only has special meaning when appearing after `$(…)`. That said, as OP mentioned, `{m,n}` is not very useful unlike `?`.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [January 16, 2018, 2:46pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/13 "2018-01-16T14:46:43Z")

</div>

I personally have seldom needed `{m,n}`. However, I would like it considered during the RFC process of adding `?`, precisely because it is included among the regex qualifiers due to sufficiently frequent need. Just because I haven’t needed it doesn’t mean that others won’t need it.

---

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [January 16, 2018, 4:46pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/14 "2018-01-16T16:46:21Z")

</div>

> [@Tom-Phinney](#):
>
> I personally have seldom needed {m,n}. However, I would like it considered during the RFC process of adding ?, precisely because it is included among the regex qualifiers due to sufficiently frequent need. Just because I haven’t needed it doesn’t mean that others won’t need it.

After thinking about it, I don't think `{m,n}` should be included in the RFC. `{m,n}` is meaningful in regex because many regexes actually do have meaningful repeat-at-least-m-but-no-more-than-n patterns. The same is not true of code IMHO:

- Many languages have variadic or optional function arguments, but I don't know of any that have semi-variadic function that can take between m and n arguments.
- It's very rare to want to repeat some construct _syntactically_ between m and n times in the source code. Usually, people use loops. One could imagine doing some sort of loop-unrolling in a macro, but this seems extremely niche.

---

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [January 16, 2018, 4:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/15 "2018-01-16T16:59:08Z")

</div>

Updated the original post again…

---

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [January 17, 2018, 5:23pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/16 "2018-01-17T17:23:57Z")

</div>

Ok, I think the conversation here seems to have settled, so I will open an actual RFC 🙂

---

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [January 17, 2018, 5:31pm UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/17 "2018-01-17T17:31:34Z")

</div>

Thanks for all the discussion!

RFC: [https://github.com/rust-lang/rfcs/pull/2298](https://github.com/rust-lang/rfcs/pull/2298)

---

<div class="post-metadata">

**Author:** ![mark-i-m](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mark-i-m/32/3167_2.png) [@mark-i-m](https://internals.rust-lang.org/u/mark-i-m)\
**Post date:** [June 30, 2018, 2:12am UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/18 "2018-06-30T02:12:47Z")

</div>

Request for comments/FCP on newest implementation: [https://github.com/rust-lang/rust/issues/51934](https://github.com/rust-lang/rust/issues/51934)

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 25, 2019, 8:29am UTC](https://internals.rust-lang.org/t/pre-rfc-at-most-one-repetition-macro-patterns/6557/19 "2019-03-25T08:29:31Z")

</div>

Closed on March 25, 2019, 8:29am UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
