# Pre-RFC: Variadic Generics

**URL:** <https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123>\
**Category:** language design\
**Created:** [April 9, 2020, 4:28pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123 "2020-04-09T16:28:16Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![alexanderlinne](https://avatars.discourse-cdn.com/v4/letter/a/82dd89/32.png) [@alexanderlinne](https://internals.rust-lang.org/u/alexanderlinne)\
**Post date:** [April 9, 2020, 4:28pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/1 "2020-04-09T16:28:16Z")

</div>

Hi, I wrote an RFC for adding variadic generics to Rust which is roughly based on [rust-lang/rfcs#2775](https://github.com/rust-lang/rfcs/issues/2775) and inspired by C++'s variadic templates. I tried to find a syntax that is not ambiguous with range expressions and fits well within the existing pattern matching syntax.

[Rendered](https://github.com/alexanderlinne/rfcs/blob/variadic_generics/text/0000-variadic-generics.md)

Any feedback is very much appreciated

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [April 9, 2020, 4:42pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/2 "2020-04-09T16:42:23Z")

</div>

previously in variadic generics

> [@Pre-RFC: variadic tuple](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878):
>
> Hi, I wrote a pre-RFC about variadic tuple, a solution for variadic generics that I think more suitable for Rust. This is based on previous work made on the variadic generics. All feedbacks are appreciated, so feel free to comment the PR here: [https://github.com/rust-lang/rfcs/pull/2775](https://github.com/rust-lang/rfcs/pull/2775)

> [@Variadic generics - pre-RFC](https://internals.rust-lang.org/t/variadic-generics-pre-rfc/8619):
>
> I’d love get some feedback on my pre-RFC for variadic generics. slight_smile This RFC is highly inspired by the draft made by @eddyb ([https://github.com/rust-lang/rfcs/issues/376](https://github.com/rust-lang/rfcs/issues/376)).

> [@Pre-RFC: #\[repr(rust)\] variadic functions](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/2):
>
> Variadic functions in a single type is not the big issue. We can model that with slices, or if we need owned values, we can use iterators. If const generics lands, we could also use arrays. Its generic variadics that needs solving. Where each element in the variadic can be a different type.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [April 9, 2020, 5:06pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/3 "2020-04-09T17:06:53Z")

</div>

> Tuple Helper Functions

I don't think we need to move forward with these just yet, it would be better to get some sort of variadic generics before these extensions.

> ```rust
> fn zip<(A @ ..), (B @ ..)>((a: A) @ .., (b: B) @ ..)
> -> ((A, B) @ ..)
> {
> ((a, b) @ ..)
> }
> 
> ```

What happens if the two tuples are different lengths? Hint: it shouldn't be a post-monomorphization error, because that would run counter to how Rust handles generics.

> ```rust
> fn all<T @ ..>((t @ ..): (T @ ..))
> -> bool
> where (T: Into<bool> + Copy) @ ..
> {
> (t.into() && ..)
> }
> 
> ```

It would be better if this took a closure as an argument, but that would require generics closures.

> For generic type parameter `IDENTIFIER@..` or `(IDNTIFIER@..)` the identifier declares a _type parameter pack_

How would this interact with pattern matching? i.e. `let x @ .. = ..;` is valid syntax right now, as is fn `foo(x @ ..: ..)` at the very least, this should use `...` to get around this, but that will have to be bounded on an edition, because 3 dots is valid in patterns.

> ```rust
> fn foo<A@..>(a: A@..) // => fn foo<A1, A2, B>(a1: A1, a2: A2)
> fn foo<A@..>((a: A)@..) // => fn foo<A1, A2, B>(a1: A1, a2: A2)
> fn foo<A@..>(a: (A@..)) // => fn foo<A1, A2, B>(a: (A1, A2))
> 
> ```

Are these all missing a `B` in the comments? Shouldn't it be

```rust
fn foo<A@..>(a: A@..) // => fn foo<A1, A2, B>(a1: A1, a2: A2, a3: B)
fn foo<A@..>(a: (A@..)) // => fn foo<A1, A2, B>(a: (A1, A2, B))

```

> ```rust
> fn foo<A@..>((a: A)@..) // => fn foo<A1, A2, B>(a1: A1, a2: A2)
> fn foo<(A@..)>(a: (A@..)) // => fn foo<(A1, A2), B>(a: (A1, A2))
> 
> ```

I don't think that these should be valid syntax. For the first, I don't see the value in two different ways to express the exact same thing. For the second, I don't see the use case for it.

> ```rust
> fn foo<A@.., B@..>((a: A)@.., (b: B)@..) // => ERROR: multiple type parameter packs
> fn foo<(A@..), B@..>((a: A)@.., (b: B)@..) // => ERROR: multiple function argument expansions
> 
> ```

instead of making these errors, we could say, in order to specify type parameter packs, you must provide a tuple. This also removes the need for the `(A@..)` syntax, and makes things unambigious.

```rust
foo::<(A, B, C), (D, E, F)>

```

> ```rust
> fn foo<A>((a@..): A) // => fn foo<(A1, A2)>((a1, a2): (A1, A2))
> 
> ```

This should be an error, we should only allow unpacking type parameter packs, not normal generic parameters.

> ```rust
> fn foo<A@(..)>(a: A) // => fn foo<(A1, A2)>(a: (A1, A2))
> 
> ```

This seems to be closest to my desired syntax. (Which i will show at the end)

> Implementation

I don't think we need to cover how to implement this, only how it is specified.

```rust
fn foo<A...>(a: A) { todo!() }
fn bar<A..., B...>(a: (...A), b: (...B)) { todo!() }

bar((0, "".to_string()), (0, Bar))

```

---

<div class="post-metadata">

**Author:** ![alexanderlinne](https://avatars.discourse-cdn.com/v4/letter/a/82dd89/32.png) [@alexanderlinne](https://internals.rust-lang.org/u/alexanderlinne)\
**Post date:** [April 9, 2020, 6:07pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/4 "2020-04-09T18:07:58Z")

</div>

> [@RustyYato](#):
>
> I don't think we need to move forward with these just yet, it would be better to get some sort of variadic generics before these extensions.

These are just examples. I do not propose to add such functions with this RFC. That's why they are in the Motivation chapter.

> [@RustyYato](#):
>
> What happens if the two tuples are different lengths? Hint: it shouldn't be a post-monomorphization error, because that would run counter to how Rust handles generics.

Pack expansions and fold expressions with multiple parameter packs mentioned require those to have the same length. (See the last point [here](https://github.com/alexanderlinne/rfcs/blob/variadic_generics/text/0000-variadic-generics.md#semantics))

> [@RustyYato](#):
>
> > For generic type parameter `IDENTIFIER@..` or `(IDNTIFIER@..)` the identifier declares a _type parameter pack_
> 
> How would this interact with pattern matching? i.e. `let x @ .. = ..;` is valid syntax right now, as is fn `foo(x @ ..: ..)` at the very least, this should use `...` to get around this, but that will have to be bounded on an edition, because 3 dots is valid in patterns. se that would run counter to how Rust handles generics.

This only talks about the type parameter lists of generic functions. AFAIK there's currently no form of pattern matching allowed there.

> [@RustyYato](#):
>
> Are these all missing a `B` in the comments? Shouldn't it be
> 
> ```rust
> fn foo<A@..>(a: A@..) // => fn foo<A1, A2, B>(a1: A1, a2: A2, a3: B)
> fn foo<A@..>(a: (A@..)) // => fn foo<A1, A2, B>(a: (A1, A2, B))
> 
> ```

Correct, must have overlooked that.

> [@RustyYato](#):
>
> > ```rust
> > fn foo<A@..>((a: A)@..) // => fn foo<A1, A2, B>(a1: A1, a2: A2)
> > fn foo<(A@..)>(a: (A@..)) // => fn foo<(A1, A2), B>(a: (A1, A2))
> > 
> > ```
> 
> I don't think that these should be valid syntax. For the first, I don't see the value in two different ways to express the exact same thing. For the second, I don't see the use case for it.

Regarding the first: I don't like that there's two way to express this either. This comes from the idea to make paranthesis in front of an @.. optional. (See [Unresolved Questions](https://github.com/alexanderlinne/rfcs/blob/variadic_generics/text/0000-variadic-generics.md#unresolved-questions)) Personally, I would prefer `fn foo<A@..>((a: A)@..)` as it is more consistent with the rest of the syntax. (`(a: A)@..` unfolds to `a1: A1, a2: A2, ...`´.

Regarding the second: i do not see a use-case for this either. If the parameter pack is used inside the function I would write `fn foo<A@(As@..)>(a: A)`. (A matches the whole tuple, As the single elements) That this is possible just comes from the fact, that you can create a type parameter pack by matching with a tuple type similar to `let (head, tail@..) = (1, 2, 3, 4)`.

> [@RustyYato](#):
>
> > ```rust
> > fn foo<A@.., B@..>((a: A)@.., (b: B)@..) // => ERROR: multiple type parameter packs
> > fn foo<(A@..), B@..>((a: A)@.., (b: B)@..) // => ERROR: multiple function argument expansions
> > 
> > ```
> 
> instead of making these errors, we could say, in order to specify type parameter packs, you must provide a tuple. This also removes the need for the `(A@..)` syntax, and makes things unambigious.
> 
> ```rust
> foo::<(A, B, C), (D, E, F)>
> 
> ```

This would be possible. Personally I think it would be more intuitive to be able to write and use a variadic function without the need for tuples as e.g. a non-variadic function `add::<A, B>` would naturally extend to `add::<A, B, C>` not `add::<(A, B, C)>`. Also - at least I think that - all functions in Rust that are currently generated using macros could then not be relaced by variadics without breaking the code. I do not know if that would be an issue.

> [@RustyYato](#):
>
> > ```rust
> > fn foo<A>((a@..): A) // => fn foo<(A1, A2)>((a1, a2): (A1, A2))
> > 
> > ```
> 
> This should be an error, we should only allow unpacking type parameter packs, not normal generic parameters.

I will change that.

> [@RustyYato](#):
>
> > ```rust
> > fn foo<A@(..)>(a: A) // => fn foo<(A1, A2)>(a: (A1, A2))
> > 
> > ```
> 
> This seems to be closest to my desired syntax. (Which i will show at the end)

Just for clarification: Here A would be a tuple type, not a type parameter pack. So @(..) is basically a constraint on A to be a tuple type.

> [@RustyYato](#):
>
> > Implementation
> 
> I don't think we need to cover how to implement this, only how it is specified.

I will remove this.

> [@RustyYato](#):
>
> ```rust
> fn foo<A...>(a: A) { todo!() }
> fn bar<A..., B...>(a: (...A), b: (...B)) { todo!() }
> 
> bar((0, "".to_string()), (0, Bar))
> 
> ```

So first, I do not think using `...` fits Rust's current syntax. Rust uses `..` everywhere else. Also for bar it would be quite unclear how you would take a function pointer to it. Is A... a tuple type? If so, this is not clear from the syntax.

I also briefly discussed this design [here](https://github.com/alexanderlinne/rfcs/blob/variadic_generics/text/0000-variadic-generics.md#t-instead-of-t-for-types).

---

<div class="post-metadata">

**Author:** ![JeffBurdges](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jeffburdges/32/2116_2.png) [@JeffBurdges](https://internals.rust-lang.org/u/JeffBurdges)\
**Post date:** [April 9, 2020, 6:24pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/5 "2020-04-09T18:24:19Z")

</div>

You could make a type that acts like `Vec<dyn Any+Sized>`, or really for any `dyn Trait+Sized`, by decomposing the `dyn Trait+Sized` fat pointers and exploiting their sizes, all with one heap allocation:

```rust
pub struct DynVec { .. }

impl DynVec {
    fn len(&self) -> usize { .. }
    fn push<T: Any+Sized>(&mut self, value: T) { .. }
}

impl Index<usize> for DynVec {
    type Output = dyn Any+Sized;
    fn index(&self, index: usize) -> &Self::Output { .. }
}
impl IndexMut<usize> for DynVec { .. }

impl<'a> IntoIterator for &'a DynAdic {
    type Item = &'a dyn Any+Sized;
    ..
}

```

I think `Index<Range<usize>>` cannot work because `Index::index` returns a fat pointer.

We'd need allocations around varadic methods anyways normally, so maybe such approaches avoid the complexity without undo overhead.

---

<div class="post-metadata">

**Author:** ![alexanderlinne](https://avatars.discourse-cdn.com/v4/letter/a/82dd89/32.png) [@alexanderlinne](https://internals.rust-lang.org/u/alexanderlinne)\
**Post date:** [April 9, 2020, 7:09pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/6 "2020-04-09T19:09:36Z")

</div>

> [@JeffBurdges](#):
>
> We'd need allocations around varadic methods anyways normally, so maybe such approaches avoid the complexity without undo overhead.

Why would we need allocations? Variadic generics would use monomorphization just like generics already do. Also just like generics they would therefore have no runtime overhead.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 9, 2020, 8:04pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/7 "2020-04-09T20:04:25Z")

</div>

I definitely look forward to having variadic generics at some point in the future.

And while I don't want to discourage design on this, I do want to set expectations that I personally\* would be surprised if lang were to take action on this in the near future. I suspect that it logistically would end up sequenced behind basic const generics, at least.

\* I haven't done anything to confirm this broadly, so don't take this as an official team decision.

---

<div class="post-metadata">

**Author:** ![PoignardAzur](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/poignardazur/32/6464_2.png) [@PoignardAzur](https://internals.rust-lang.org/u/PoignardAzur)\
**Post date:** [April 10, 2020, 9:07am UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/8 "2020-04-10T09:07:48Z")

</div>

> [@alexanderlinne](#):
>
> Pack expansions and fold expressions with multiple parameter packs mentioned require those to have the same length. (See the last point [here](https://github.com/alexanderlinne/rfcs/blob/variadic_generics/text/0000-variadic-generics.md#semantics))

This still introduces a potential for post-monomorphization errors, which this pre-RFC under-specifies.

Tweaking your example:

```rust
fn zip_and_print<(A @ ..), (B @ ..)>((a: A) @ .., (b: B) @ ..)
{
    println!((a, b) @ ..)
}

```

There is nothing in the function's declaration which indicates that the function will fail to compile if given mismatched tuples.

Variadics probably need to some way to express "you can't do println!((a, b) @ ..)", because there is no guarantee a and b are the same size inside zip\_and\_print.

The obvious way to do that is to say "((a, b) @ ..) is only allowed if ((A, B) @ ..) is somewhere in the declaration", but that's completely unprincipled.

A better solution would probably require making a survey of variadic generics in C++ and D, their patterns of use, their anti-patterns, their failure modes, etc, and decide what we want to import into Rust.

The problem with existing "variadic generics" RFCs is that they don't really have a strong story behind them.

---

<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:** [April 10, 2020, 12:31pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/9 "2020-04-10T12:31:35Z")

</div>

> [@scottmcm](#):
>
> - I haven't done anything to confirm this broadly, so don't take this as an official team decision.

It feels about right for me at least 🙂 -- variadic generics are fairly low in the list of priorities, as I see it (if we ever do it, it would be in the order of several years from now, imo).

---

<div class="post-metadata">

**Author:** ![L0uisc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/l0uisc/32/6707_2.png) [@L0uisc](https://internals.rust-lang.org/u/L0uisc)\
**Post date:** [April 10, 2020, 1:03pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/10 "2020-04-10T13:03:59Z")

</div>

This might be a nice feature, but IMHO it should first be thought through very thoroughly. Rust is a powerful language with lots of nice features. However, the sheer amount of features are already overwhelming to beginners sometimes. Variadic generics will most certainly add to that load of things a newbie should learn.

While I didn't read the proposal in detail, similar code should be possible with `macro_rules!` macros, shouldn't it? It might just not be as ergonomic. Let's not go the C++ route to add 10 different ways to do everything and overload symbols for 10 different contexts. Rust will only be hurt by it. Because of its already large necessary complexity, we should really think twice about adding more of it where it isn't really clearly beneficial.

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [April 10, 2020, 1:07pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/11 "2020-04-10T13:07:42Z")

</div>

I think the syntax is unnecessarily verbose, it actually looks like another macro system. Also, `...` would be a better symbol, since it's already used for C variadic functions. Here's the alternative syntax I came up with:

```rust
pub trait Fn<Args...>: FnMut<Args...> {
    fn call(&self, params: Args...) -> Self::Output {
        func(params...)
    }
}

```

The above only requires the following features:

- **Variadic type arguments** , i.e. `trait Fn<Args...>`, where `Args` accepts multiple type arguments that are "collected" into a tuple type
- **Variadic types** , i.e. `FnMut<Args...>`, where `Args` is a tuple type that is "spread out"
- **Variadic patterns** , i.e. `fn call(&self, params: Args...)`, where `params` accepts a series of values that are "collected" into a tuple
- **Variadic tuples and function calls** , i.e. `func(params...)`, where `params` is a tuple that is "spread out"

This is only a subset of the features you are proposing, but it's simple, coherent, and integrates well with the existing type system, because everything is desugared into tuples:

```rust
struct Foo<T...>(T...);

let tuple = (2, 3, '5');
assert_eq!(Foo(1, tuple...), Foo(1, 2, 3, '5'));
assert_matches!(tuple, (2, _...));

```

This idea could be extended later to allow trait bounds on the tuple items, but it is intentionally very simple.

Prior art: [Javascript spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)

P.S. this would require a new edition where the `...` inclusive range pattern (which currently emits a deprecation warning) is removed.

---

<div class="post-metadata">

**Author:** ![alexanderlinne](https://avatars.discourse-cdn.com/v4/letter/a/82dd89/32.png) [@alexanderlinne](https://internals.rust-lang.org/u/alexanderlinne)\
**Post date:** [April 11, 2020, 12:20am UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/12 "2020-04-11T00:20:53Z")

</div>

> [@scottmcm](#):
>
> And while I don't want to discourage design on this, I do want to set expectations that I personally\* would be surprised if lang were to take action on this in the near future. I suspect that it logistically would end up sequenced behind basic const generics, at least.

I wasn't aware of that. In the "Variadic Tuple" RFC I linked in my first post and the discussions on that in this forum const generics were only mentioned once. Also from the discussion I personally got the impression that variadics is a wanted feature.

If a RFC on variadic generics would currently have no chance of being merged anyways, I'm fine with abandoning it. Yet, I would also be happy discussing it if it would have a chance of success. As I'm completely new here, you would have to tell me. But yours and also @Centril's post pretty much give me the impression that it won't - at the moment at least.

---

<div class="post-metadata">

**Author:** ![alexanderlinne](https://avatars.discourse-cdn.com/v4/letter/a/82dd89/32.png) [@alexanderlinne](https://internals.rust-lang.org/u/alexanderlinne)\
**Post date:** [April 11, 2020, 12:38am UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/13 "2020-04-11T00:38:07Z")

</div>

> [@PoignardAzur](#):
>
> ```rust
> fn zip_and_print<(A @ ..), (B @ ..)>((a: A) @ .., (b: B) @ ..)
> {
> println!((a, b) @ ..)
> }
> 
> ```
> 
> There is nothing in the function's declaration which indicates that the function will fail to compile if given mismatched tuples.

Actually, `(a, b) @ ..` is a pack expansion and therefore requires a and b to have the same size. This in turn also requires A and B to have the same size.

Similar code in C++ would look like this:

```rust
template<class ...A, class ...B, size_t ...AIdx, size_t ...BIdx>
void zip_impl(
    std::tuple<A...> a, std::tuple<B...> b,
    std::index_sequence<AIdx...>, std::index_sequence<BIdx...>)
{
    auto zipped = std::make_tuple(std::make_pair(std::get<AIdx>(a), std::get<BIdx>(b))...);
}

template<class ...A, class ...B>
void zip(std::tuple<A...> a, std::tuple<B...> b)
{
    zip_impl(a, b, std::index_sequence_for<A...>{}, std::index_sequence_for<B...>{});
}

```

when you'd call `zip_and_print(std::make_tuple(1, 2, 3), std::make_tuple('a', 'b'))` you'd get this error (with clang 9):

```rust
test.cpp:25:87: error: pack expansion contains parameter packs 'AIdx' and 'BIdx' that have different lengths (3 vs. 2)
    auto zipped = std::make_tuple(std::make_pair(std::get<AIdx>(a), std::get<BIdx>(b))...);
                                                          ~~~~ ^
test.cpp:31:5: note: in instantiation of function template specialization 'zip_and_print_impl<int, int, int, char, char, 0, 1, 2, 0, 1>' requested here
    zip_and_print_impl(a, b, std::index_sequence_for<A...>{}, std::index_sequence_for<B...>{});
    ^
test.cpp:38:5: note: in instantiation of function template specialization 'zip_and_print<int, int, int, char, char>' requested here
    zip_and_print(std::make_tuple(1, 2, 3), std::make_tuple('a', 'b'));
    ^
1 error generated.

```

The error for your example would be something similar. In C++ you could also explicitly require this using either `std::enable_if`, `static_assert` or with C++20 a `requires`-clause, i.e.

```rust
template<class ...A, class ...B>
void zip_and_print(std::tuple<A...> a, std::tuple<B...> b)
    requires sizeof...(A) == sizeof...(B)

```

That's why I added [this section](https://github.com/alexanderlinne/rfcs/blob/variadic_generics/text/0000-variadic-generics.md#checks-of-a-parameter-packs-arity).

> [@PoignardAzur](#):
>
> A better solution would probably require making a survey of variadic generics in C++ and D, their patterns of use, their anti-patterns, their failure modes, etc, and decide what we want to import into Rust.
> 
> The problem with existing "variadic generics" RFCs is that they don't really have a strong story behind them.

I intentionally kept my proposal very close to how C++'s variadic templates work, because that's where I'm coming from and IMHO they work really well and are very intuitive to work with. (I initially stumbled across this because I searched for something similar to Boost.Signals2 in Rust.)

---

<div class="post-metadata">

**Author:** ![alexanderlinne](https://avatars.discourse-cdn.com/v4/letter/a/82dd89/32.png) [@alexanderlinne](https://internals.rust-lang.org/u/alexanderlinne)\
**Post date:** [April 11, 2020, 1:11am UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/14 "2020-04-11T01:11:12Z")

</div>

> [@Aloso](#):
>
> pub trait Fn\<Args...\>: FnMut\<Args...\> { fn call(&self, params: Args...) -\> Self::Output { func(params...) } }

This looks pretty close to [rust-lang/rfcs#376](https://github.com/rust-lang/rfcs/issues/376). In general, multiple of the prior RFCs on this have already proposed syntax similar to `params...`. The problem is that even if you could resolve ambiguity by using three dots, this syntax would still be pretty close to range expressions. If param only needs to be a tuple type to be unfolded this way, then `(0,)..` (which is valid today) and `(0,)...` would be valid syntax. That's the reason I tried to find a different syntax for this.

But:

> [@L0uisc](#):
>
> While I didn't read the proposal in detail, similar code should be possible with `macro_rules!` macros, shouldn't it?

I do think that some, or even much, of what I am proposing could be replaced with macros. Personally I think that syntax for this would probably be easier to use. (Again, I'm coming from the world of C++, I'm more used to their syntax.) In RFC#2775 in [this post](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/38) you (@Aloso) suggested a repeat! built-in macro. With that you could write:

```rust
fn print<..A>(a: ..A)
{
    repeat!(for v in a { println!(a); })
} 

```

In my proposal that would simply be `(println!(a) @ ..)`. IMO there at least should be a simple, built-in way to unfold not only parameter packs alone, but expressions as in `(a, b) @ .. => (a1, b1), (a2, b2), ...`.

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [April 11, 2020, 1:57am UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/15 "2020-04-11T01:57:46Z")

</div>

> [@alexanderlinne](#):
>
> Actually, `(a, b) @ ..` is a pack expansion and therefore requires a and b to have the same size. This in turn also requires A and B to have the same size.

Yes, but there's nothing in the _declaration_ that requires this. The error would thus be post-monomorphization; in other words, it happens at template instantiation time. In C++, instantiation-time errors are the norm; these days you can stick in `requires` clauses (and in the past you could use `enable_if`, `static_assert`, etc.), but even then, nothing ensures that the requirements you wrote match the actual usage in the template body, so you can still get instantiation-time errors even if the requirements are satisfied. In Rust, the compiler type-checks generics when they're declared; you can only use operations that match the declared trait bounds, so instantiation-time errors are impossible, with only minor exceptions.

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [April 11, 2020, 9:04pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/16 "2020-04-11T21:04:54Z")

</div>

> [@alexanderlinne](#):
>
> In my proposal that would simply be `(println!(a) @ ..)`

I find that a bit confusing, because it's not immediately clear which parts of the expression are unfolded. For example, if you have the following code, and `a` is a parameter pack, but `b` is not:

```rust
(println!("{}{}", a, b) @ ..)

```

Then `a` would be unfolded, but `b` would just be repeated. Although this is similar to how `macro_rules!` works, I'd prefer to be explicit about which values are unfolded.

Also, I'd like to avoid introducing another declarative macro system (which the language team probably wouldn't approve anyway; they are usually against language features that are likely very difficult/time consuming to implement/learn, unless their benefit is remarkable).

---

<div class="post-metadata">

**Author:** ![alexanderlinne](https://avatars.discourse-cdn.com/v4/letter/a/82dd89/32.png) [@alexanderlinne](https://internals.rust-lang.org/u/alexanderlinne)\
**Post date:** [April 11, 2020, 10:11pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/17 "2020-04-11T22:11:42Z")

</div>

Thanks for the clarification. The best (and probably easiest) solution I could come up with would be using the following trait (assuming ..A for declaring a parameter pack):

```rust
trait SameArityAs<T> {}
impl SameArityAs<()> for () {}
impl<A, (..As), B, (..Bs)> SameArityAs<(A, ..As)> for (B, ..Bs)
    where (..As): SameArityAs<(..Bs)>
{}

```

with that you could write:

```rust
fn zip_and_print<(..A), (..B)>(a: ..A, b: ..B)
    where (..A): SameArityAs<(..B)>
{
    println!((a, b) @ ..)
}

```

If such unfoldings are then only allowed with this trait bound, this should be an error during monomorphization, correct?

---

<div class="post-metadata">

**Author:** ![PoignardAzur](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/poignardazur/32/6464_2.png) [@PoignardAzur](https://internals.rust-lang.org/u/PoignardAzur)\
**Post date:** [April 12, 2020, 9:34am UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/18 "2020-04-12T09:34:45Z")

</div>

> [@alexanderlinne](#):
>
> Thanks for the clarification. The best (and probably easiest) solution I could come up with would be using the following trait (assuming ..A for declaring a parameter pack):
> 
> ```rust
> trait SameArityAs<T> {}
> impl SameArityAs<()> for () {}
> impl<A, (..As), B, (..Bs)> SameArityAs<(A, ..As)> for (B, ..Bs)
> where (..As): SameArityAs<(..Bs)>
> {}
> 
> ```

That's the obvious solution, yes, but it's also a band-aid.

What about cases where you want to concatenate tuples? Or combine them in some other non-obvious way?

A proper RFC would need to make a survey of what will and will not be possible with variadic generics. That survey should be based around existing use-cases in other languages, and have rules designed to fail gracefully (that is, the compiler should be able to explain to users where they made a mistake).

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [April 12, 2020, 10:21pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/19 "2020-04-12T22:21:15Z")

</div>

> [@PoignardAzur](#):
>
> What about cases where you want to concatenate tuples? Or combine them in some other non-obvious way?

This could be solved with a built-in trait, once const generics are stabilized:

```rust
pub trait Arity {
    const ARITY: usize;
}

```

Since specifying the arity is in the _future possibilities_ sections, I guess this is not a priority. However, I have identified some other issues:

1. I noticed that the grammar is ambiguous in some situations:

2. Parsing multiple paramter packs can be ambiguous:

3. The grammar is incomplete and vague. From the `nomenclature` section:

4. The semantics aren't always clear:

5. For consistency, it should be possible to have variadic, but non-generic types, e.g.

6. Should it be possible to have variadic lifetimes? E.g.

7. Should it be possible to pass pack expansions to `macro_rules!` macros? It could look like this:

---

<div class="post-metadata">

**Author:** ![alexanderlinne](https://avatars.discourse-cdn.com/v4/letter/a/82dd89/32.png) [@alexanderlinne](https://internals.rust-lang.org/u/alexanderlinne)\
**Post date:** [April 14, 2020, 7:23pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123/20 "2020-04-14T19:23:31Z")

</div>

I think some of your question show a misunderstanding of what I am fundamentally trying to achieve in my proposal. So maybe first in general: the way I came up with the syntax in my proposal was that in current Rust the following is valid syntax:

```rust
let tup@(a, .., b) = ...

```

and my initial idea was that you could allow to assign an identifier to .. like it is allowed in slices, i.e.. `tup@(a, as@.., b)`. From there I thought it would be intuitive if

- you would use the same syntax for type parameters and
- that when you can "collect" a parameter pack (i.e. a comma-separated list of types) by `@..` you could also "uncollect" it similarly (into a comma-separated list).

And the most important bit is this rule of thumb:

In any context, `(E(a))@..` where `E` is a type, expression, etc. mentioning a parameter pack `a`, it can be read as `E(a1), E(a2), ..., E(an)`.

What creates some confusion I think is that I made paranthesis optional on the left side of the `@` and specified that `@` would match the expression or type as far to the left as possible. This leads to the rather unintuitive situation where `a: A@..` is equivalent to `(a: A)@..`. I think it would be a better choice to make the paranthesis mandatory.

Also I found quite some placed where there should be a `,` to make it an actual tuple expression or pattern. I'll need to fix this.

Applying the "rule of thumb" to your questions:

- `A@..: Bound` would theoretically expand to `A` to `A1, A2, ..., An: Bound`. This would be disallowed, cause it's unintuitive. To put a bound on every element of the tuple you would write `(A: Bound)@..`
- `(A@..): Bound` expands `A` to `(A1, A2, .., An): Bound`, so it's a bound on the tuple type.
- `A@(..)` is basically equivalent to the above one, you just did not assign an identifier to `..` but to the full tuple. (like you could also do in my general explanation for variables where `tup` was the full tuple ans `as` was the parameter pack)
- `(A: Bound)@(..)` would be disallowed. The correct syntax here would be `A@(..): Bound`.
- For `= Bar` it's basically the same explanation as above for `: Bound`.

> [@Aloso](#):
>
> Parsing multiple paramter packs can be ambiguous

That's why in my proposal:

```rust
fn foo<(A@..), B@..>((a: A)@.., (b: B)@..) // => ERROR: multiple function argument expansions

```

> [@Aloso](#):
>
> Also, nested parameter packs like `A@..@..` must be forbidden

This is actually in the rules. Here the outer expansion would have no parameter pack within it's scope, which is forbidden. (You could also formulate this rule the other way around: each parameter pack can only be expanded once.)

> [@Aloso](#):
>
> Function arguments are **patterns** , but the proposed grammar only accepts tuple patterns, so `fn foo<A@..>((a: A)@..)` would be rejected.

How does the proposed grammer only accept tuple patterns? Actually, function parameter are not exactly patterns [according to the reference](https://doc.rust-lang.org/stable/reference/items/functions.html?highlight=function#functions). They are `OuterAttribute* Pattern : Type` which is why I gave them another name. By the rule of thumb from above `fn foo<A@..>((a: A)@..)` unfolds to `fn foo<A1, A2, ..., An>(a1: A1, a2: A2, ..., an: An)`.

> [@Aloso](#):
>
> Should it be possible to have variadic lifetimes? E.g.
> 
> ```rust
> fn foo<('a, 'b)@..>(a: ((&'a str, &'b str)@..));
> 
> ```

I think the notion of parameter packs would naturally extend to lifetimes, yes. I haven't considered that in my proposal yet. I'll add this as a todo chapter.

> [@Aloso](#):
>
> Should it be possible to pass pack expansions to `macro_rules!` macros?

As of now I would put this under future possibilities until the basic syntax is more fleshed out.

> [@Aloso](#):
>
> Since specifying the arity is in the _future possibilities_ sections, I guess this is not a priority.

I put this under future possibilities because I didn't think of those traits at the time of writing. I will add those to the document.

> [@Aloso](#):
>
> I noticed that the grammar is ambiguous in some situations:
> 
> > `FoldExpression: (Expression OPERATOR ..) | (.. OPERATOR Expression) | (Expression OPERATOR .. OPERATOR ConstantExpression) | (ConstantExpression OPERATOR .. OPERATOR Expression)`
> 
> For example, `(a / ..)` is currently parsed as `a / (..)` and `(.. + a)` is parsed as `..(+a)` .

That's true. I actually think that at least for fold expressions a macro would be better suited. Something like `fold!(a with +)`. I will put this under future possibilities.

I will update my proposal with some of your feedback. But I'll need some time for that.

[Next page](https://internals.rust-lang.org/t/pre-rfc-variadic-generics/12123.md?page=2)
