# Pre-RFC: variadic tuple

**URL:** <https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878>\
**Category:** language design\
**Created:** [August 27, 2019, 8:00pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878 "2019-08-27T20:00:34Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![fredpointzero](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fredpointzero/32/6040_2.png) [@fredpointzero](https://internals.rust-lang.org/u/fredpointzero)\
**Post date:** [August 27, 2019, 8:00pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/1 "2019-08-27T20:00:35Z")

</div>

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)

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [August 27, 2019, 9:43pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/2 "2019-08-27T21:43:58Z")

</div>

I'm glad to see a proposal that isn't just cons-lists again.

My thoughts:

- Why are there different syntax forms for declaration and usage?

- There's no reason to keep using italics throughout the whole thing. Italics are for emphasis or phrases borrowed from other languages.

- The section on "Multiple identifier expansion forms" makes it feel like something is missing from the type signature. While there are exceptions, it is uncommon for something in rust to produce errors at monomorphization time.

- 

```rust
let ({ref T}#..) = values;

```

I think this should be

```rust
let ((ref T)#..) = values;

```

because `{pat}` is not a pattern, while `(pat)` is.

- In that same section, most of the headings there are not useful.

- Is it possible to use this to write a variadic Enum? (i.e. is it possible to write an enum type as a type with a tuple type argument `(A, B, C, ...)`?) It seems like it would be a shame to only cover product types without sum types.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [August 27, 2019, 10:37pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/3 "2019-08-27T22:37:35Z")

</div>

One note I want to add is that recursive variadic tuples should be explicitly allowed or disallowed. With the current given syntax, I think that'd be `<(..#(..#T))>`.

I'll take a deeper look later, but on the surface this looks promising. I just need to think through the implications of allowing `#..` basically anywhere.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [August 27, 2019, 11:18pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/4 "2019-08-27T23:18:58Z")

</div>

To me this looks like `macro_rules`, but without a macro. For example, the new `{…}#` syntax in function bodies seems to be similar to `$(…)+`. Could they be somehow unified?

Or perhaps instead of a new syntax, could there be something more conventional, like `std::tuple::for_each`/`map` macros?

```rust
    fn hash<S: Hasher>(&self, state: &mut S) {
        std::tuple::for_each! {self, |t| t.hash(state)}
    }

```

---

<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:** [August 27, 2019, 11:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/5 "2019-08-27T23:41:05Z")

</div>

@kornel they wouldn't be normal macros, but I think that is fine, as the correspondence to normal macros will make this easier to learn.

---

<div class="post-metadata">

**Author:** ![fredpointzero](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fredpointzero/32/6040_2.png) [@fredpointzero](https://internals.rust-lang.org/u/fredpointzero)\
**Post date:** [August 28, 2019, 7:11am UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/6 "2019-08-28T07:11:25Z")

</div>

> [@ExpHP](#):
>
> Why are there different syntax forms for declaration and usage?

Hi, thanks for your comments, I'll answer as I can point by point:

> - Why are there different syntax forms for declaration and usage?

I find it confusing if they both share the same syntax. By using different syntax, you know exactly what you are looking at.

> - There's no reason to keep using italics throughout the whole thing. Italics are for emphasis or phrases borrowed from other languages.

Noted, I'll update the RFC accordingly.

> - The section on "Multiple identifier expansion forms" makes it feel like something is missing from the type signature. While there are exceptions, it is uncommon for something in rust to produce errors at monomorphization time.

I like the idea you are suggesting, embedding the length constraint in the syntax itself is nice. Although it may collide with the point made by CAD97 about recursive variadic tuple, but it is worth thinking about it.

> - `let ({ref T}#..) = values;`

Noted, I wasn't sure about this, I'll update the RFC, it will make more sense for Rust users.

> - In that same section, most of the headings there are not useful.

Several points here. First of all, the section was intended to show the location where the variadic tuple can be used, not use cases of the variadic tuple. Maybe I should rephrase the section then.

> Can you splat into a function call? `(func(Tuple#..))`

No, you will use a variadic tuple as a single argument.

> Can you generate a list of statements? (maybe not? I can't picture a good syntax for it)

No, the goal is to manipulate tuples.

Although you can do something similar:

```rust
let values = (({let mut v = T::VALUE; v *= 2; v})#..);

```

will expand to

```rust
let values = ({let mut v = T1::VALUE; v *= 2; v}, {let mut v = T2::VALUE; v *= 2; v}, {let mut v = T3::VALUE; v *= 2; v});

```

for a variadic tuple instance `(T1, T2, T3)`.

> - Is it possible to use this to write a variadic Enum?

No, this is intended to be for tuples only. Handling variadic enum is, in my opinion, quite different and will have way more implications that variadic tuples. So if variadic enum needs to be implemented, I think it should be in an another RFC.

---

<div class="post-metadata">

**Author:** ![fredpointzero](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fredpointzero/32/6040_2.png) [@fredpointzero](https://internals.rust-lang.org/u/fredpointzero)\
**Post date:** [August 28, 2019, 7:13am UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/7 "2019-08-28T07:13:39Z")

</div>

Hi @CAD97, this is interesting.

For this RFC, recursive variadic tuples will not be allowed, however, this can be added in a further RFC. The only restriction I want to keep, is that the syntax chosen in this RFC will not prevent a recursive variadic tuple RFC later.

---

<div class="post-metadata">

**Author:** ![fredpointzero](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fredpointzero/32/6040_2.png) [@fredpointzero](https://internals.rust-lang.org/u/fredpointzero)\
**Post date:** [August 28, 2019, 7:19am UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/8 "2019-08-28T07:19:17Z")

</div>

Hi @kornel.

I don't think such a macro like syntax is viable, because:

- I don't think about a way of declaring `self` as a tuple.
- You will expect that this macro will follow the macro hygiene and you don't want the hygiene here.
- I think it is weird to have a macro syntax at some locations, like where bounds

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [August 28, 2019, 2:34pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/9 "2019-08-28T14:34:23Z")

</div>

> [@fredpointzero](#):
>
> I find it confusing if they both share the same syntax. By using different syntax, you know exactly what you are looking at.

Hmmm, this I just find hard to agree with. I had a difficult time writing those examples because the difference feels arbitrary.

We don't have special declaration syntax for type parameters or lifetime parameters. (just the regular syntax, with the optional addition of bounds). `const` generics have different syntax for declaration and usage, but that serves a number of purposes (specifying the type of the const; and making parsing tractable when types appear in expressions), and they mirror items and expressions so they are easy to remember.

> [@fredpointzero](#):
>
> Several points here. First of all, the section was intended to show the location where the variadic tuple can be used, not use cases of the variadic tuple. Maybe I should rephrase the section then.

It looks to me precisely like you _are_ listing use cases. Expressions, patterns, and types are fundamental parts of the language. Function argument types, return types, struct member types etc. are all just specific instances of types with the same grammar.

I think it'd be easier to list the places where they _cannot_ be used... if there even are any!

> [@fredpointzero](#):
>
> ```rust
> let values = (({let mut v = T::VALUE; v *= 2; v})#..);
> 
> ```

On seeing this I'd just like to clarify: when I suggested `(ref T)#..` over `{ref T}#..`, that was specifically for patterns and types. `{ }#` (creating a block scope for each value) makes perfect sense for expressions.

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [August 28, 2019, 2:34pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/10 "2019-08-28T14:34:39Z")

</div>

You mention C++ parameter packs in your RFC, and I feel like they should be strongly comparable to what you're suggesting, but I'm failing to make the comparison. Could you explain how your idea is similar or completely different from C++ parameter packs (in particular, their first-class form in C++17).

---

<div class="post-metadata">

**Author:** ![fredpointzero](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fredpointzero/32/6040_2.png) [@fredpointzero](https://internals.rust-lang.org/u/fredpointzero)\
**Post date:** [August 28, 2019, 8:33pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/11 "2019-08-28T20:33:40Z")

</div>

I updated the RFC accordingly to your feedbacks:

1. Both the expansion and declaration form have the same syntax. Let's see if this is less confusing that way.
2. You can define multiple variadic tuple in the same declaration with `(..#(T1, T2))`, in that case all variadic tuple will have the same arity. This syntax avoids to handle invalid arity error by the compiler.
3. The expansion form can be enclosed by either braces or parenthesis (or nothing, if it is simple).

I will add later an error concerning expansion errors that uses multiple variadic tuple identifiers that were not declared together.

---

<div class="post-metadata">

**Author:** ![fredpointzero](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fredpointzero/32/6040_2.png) [@fredpointzero](https://internals.rust-lang.org/u/fredpointzero)\
**Post date:** [August 28, 2019, 8:46pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/12 "2019-08-28T20:46:01Z")

</div>

I am not an expert concerning C++ parameter packs, but the design around it inspired this RFC and the previous one concerning the variadic generics.

Basicaly, variadic tuples and parameters packs are quite similar. In a few word, variadics tuple are parameters packs enclosed by parenthesis.

So the major difference is that you will always manipulate a tuple with variadic tuple, while you manipulate a set of types with parameter packs. If you look at the RFC, any declaration form or expansion form will result in a tuple.

This makes possible to use multiple variadic tuple in a declaration and easily "join" them. (See the `MegaMap` example).

Finally, one of the goal of this RFC is also to empower the usage of tuple in Rust (and that is specific to the way Rust implemented tuples). So this is another reason to focus more on tuples here.

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [August 28, 2019, 11:29pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/13 "2019-08-28T23:29:39Z")

</div>

I think it would help if you could find some usages of C++ parameter packs and contrast them to your proposal. In C++, a parameter pack is nothing more than a tuple of types; `std::tuple<>` is really "let's make a struct that has a parameter pack as a member variable". I agree we should focus on built-in tuples, since we already have them, and it allows for things C++ doesn't easily allow, such as multiple parameter packs in a definition. However, I think it would be useful if you could find some C++ examples and express something equivalent to them in this proposal. For example, how would I write

```rust
// C++ for trait Named { const NAME: &str; }, roughly
template <typename T>
concept Named = requires(T) {
  { T::kName } -> std::string_view;
}

// Returns a vector of the names of the types |Ts|.
template <typename... Ts>
  requires Named<Ts>...
std::vector<std::string_view> Names() {
  return std::vector{Ts::kName...};
}

```

Relatedly, can you explain what `(..#T)` is, syntactically? It looks like you use it as a type parameter, a pattern, and an expression in different places. What are the allowed forms of `T` in each? I get the impression that as a type parameter, you're allowed to write `(..#(T, U))`. Might it make sense to also allow writing `struct Foo<(T, U)>`, as a sort of "type-level pattern matching"?

Can I write something like

```rust
type T = (int, int);
struct K<(..#T)> { .. };
type L = K<T>;

```

Also, can you address the case of single-element tuples? If I have `struct K<(..#T)>`, can I write `K<(int)>`, or must I write `K<(int,)>`?

---

<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:** [August 28, 2019, 11:34pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/14 "2019-08-28T23:34:37Z")

</div>

> [@mcy](#):
>
> Also, can you address the case of single-element tuples? If I have `struct K<(..#T)>` , can I write `K<(int)>` , or must I write `K<(int,)>` ?

This would be `K<(int,)>` to stay consistent with current behavior. `(int)` is always the same as `int` today, and that should not change due to this proposal.

---

<div class="post-metadata">

**Author:** ![fredpointzero](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fredpointzero/32/6040_2.png) [@fredpointzero](https://internals.rust-lang.org/u/fredpointzero)\
**Post date:** [August 29, 2019, 7:29am UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/15 "2019-08-29T07:29:11Z")

</div>

> [@mcy](#):
>
> I think it would help if you could find some usages of C++ parameter packs and contrast them to your proposal.

If you can provide some example like you did, I will appreciate. I can add then in an appendix in the end for C++ users to have a reference to compare to. (My C++ experience is old so I will need quite some time to catch up and find appropriate syntax examples otherwise

> [@mcy](#):
>
> n C++, a parameter pack is nothing more than a tuple of types; `std::tuple<>` is really "let's make a struct that has a parameter pack as a member variable".

)

So I guess that variadic tuples can be compared to C++'s `std::tuple<>`.

> [@mcy](#):
>
> Relatedly, can you explain what `(..#T)` is, syntactically?

Syntactically, `(..#T)` is different depending on the usage location. Inside generic parameter groups (declaration form):

- For this syntax: `(..#T)`, then `..#T` defines a list of types identified by `T` and `(..#T)` is a tuple type made with the list of type `..#T`.
- For this syntax: `(..#(A, B))`, `..#(A, B)` is a list of 2-tuple types and `(..#(A, B))` is a tuple type made with the list of 2-tuple type `..#(A, B)`

Note 1: `(..#(A, B))` can be considered as a type-level pattern matching a tuple type with only 2-tuple members.

Note 2: This kind of type-level pattern matching is only works for tuple, ie `(..#(A, Vec<B>))` is not valid.

Note 3: For the syntax `(..#(A, B))`, `..#(A, B)` is a list of 2-tuple types, `..#A` is a list of type and `..#B` is a list of type as well.

At any other location (expansion form): Let's consider the `MegaMap` example:

```rust
struct MegaMap<(..#(K, V))> {
    maps: (..#HashMap<K, V>),
}

```

`HashMap<K, V>` is an expression using identifiers `K` and `V`. I am not sure about `(..#HashMap<K, V>)` though, but I'd say it is an expression as well.

Note: I will update the RFC to clarify the syntax role of each element, and the type pattern matching in declarative form

---

<div class="post-metadata">

**Author:** ![lordan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lordan/32/2107_2.png) [@lordan](https://internals.rust-lang.org/u/lordan)\
**Post date:** [August 29, 2019, 12:30pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/16 "2019-08-29T12:30:27Z")

</div>

A good overview of C++ parameter packs is at [https://en.cppreference.com/w/cpp/language/parameter\_pack](https://en.cppreference.com/w/cpp/language/parameter_pack)

In C++ there are _type parameter packs_, which are almost the same as yours, and _function parameter packs_, which are missing from your proposal AFAICT (FWIW there are also template template parameter packs, and non-type template parameter packs). Parameter packs are "collected" (declared) with a prefix `...`, and expanded with postfix `...`.

Crucially, I think this

```rust
fn double<(..#T)>(input: (..#T)) -> (..#T)
	where ..#(T: Add), {
    (..#(T + T))
}

```

would not really work, unless I'm misunderstanding something. First,

```rust
fn double<(..#T)>(input: (..#T)) -> (..#T)

```

AFAICT should really be (?):

```rust
fn double<(..#T)>(input: (..#T)) -> (T#..)

```

but especially:

```rust
 (..#(T + T))

```

doesn't make sense to me: `T` is/are type(s), not values, and thus can't be added.

For reference, the C++ equivalent would be (off the top of my head):

```cpp
template<typename ...Ts> // type parameter pack
std::tuple<Ts...> // expand in return type
tupledouble(Ts ... input) { // function parameter pack
    return std::make_tuple((input + input)...); // expand parameter pack
}

```

Note C++ also has neat fold expressions, e.g., to sum all values:

```cpp
return input + ...; // right fold, i.e. input_1 + input_2 + ... + input_n
return ... + input; // left fold
return input + ... + 0; // right fold with initial value
return 0 + ... + input; // left fold with initial value

```

---

<div class="post-metadata">

**Author:** ![fredpointzero](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fredpointzero/32/6040_2.png) [@fredpointzero](https://internals.rust-lang.org/u/fredpointzero)\
**Post date:** [August 29, 2019, 1:43pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/17 "2019-08-29T13:43:42Z")

</div>

Thanks for the information I appreciate!

> [@lordan](#):
>
> ```rust
> fn double<(..#T)>(input: (..#T)) -> (..#T)
> 
> ```
> 
> AFAICT should really be (?):
> 
> ```rust
> fn double<(..#T)>(input: (..#T)) -> (T#..)
> 
> ```

Actually, the original design used `(..#T)` as declaration form and `(T#..)` as expansion form, but some people were confused by this syntax, so I kept the same syntax for both form.

For me, I prefer to have different syntax as it sounds clearer to me, but this is not the case in a lot of Rust syntax (for instance tuple declaration and destructuring tuples have extremely close syntax).

> [@lordan](#):
>
> but especially:
> 
> ```rust
> (..#(T + T))
> 
> ```
> 
> doesn't make sense to me: `T` is/are type(s), not values, and thus can't be added.

That is indeed a major issue. So I think it can be fixed the same way C++ does:

Instead of

```rust
fn double<(..#T)>(input: (..#T)) -> (..#T)
	where ..#(T: Add), {
    (..#(T + T))
}

```

We can use

```rust
fn double<(..#T)>(input: (..#T)) -> (..#T)
	where ..#(T: Add), {
    (..#(input + input))
}

```

I think that can be tuple expansion rule that happens at compile time. This can be done for any tuple (variadic or fixed).

```rust
let my_tuple = (1, "Hello World!", true);
let my_string_tuple = (..#{ format!("{}", my_tuple) });
// let my_string_tuple = ({ format!("{}", my_tuple.0) }, { format!("{}", my_tuple.1) }, { format!("{}", my_tuple.2) });

```

Concerning the syntax, then `(..#T)` is a _variadic tuple type_, and `index` in `index: (..#T)` is a _variadic tuple_.

What do you think about this?

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [August 29, 2019, 1:44pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/18 "2019-08-29T13:44:41Z")

</div>

Obviously, but I mention it because it looks rather ugly, doesn't it?

---

<div class="post-metadata">

**Author:** ![lordan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lordan/32/2107_2.png) [@lordan](https://internals.rust-lang.org/u/lordan)\
**Post date:** [August 29, 2019, 1:52pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/19 "2019-08-29T13:52:56Z")

</div>

TBH, `input: (..#T)` reads to me as a single parameter `input` that captures a single tuple of arbitrary length, i.e., not a parameter pack.

The C++ syntax doesn't translate very well (FWIW, despite all the ugly syntax in C++, variadic templates and fold expressions are one of the neater syntaxes, IMHO). I think you'd need an outer parameter that captures the whole tuple (`input` in our example), and a new syntax to capture individual elements, e.g., `input: (i: ..#T)`, then expand with `..#(i + i)`.

On the plus side, this retains the ability to have multiple parameter packs in a call/expression, something that C++ can't do, and allow you to address the whole tuple via `input`, too, which may come in handy.

---

<div class="post-metadata">

**Author:** ![fredpointzero](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/fredpointzero/32/6040_2.png) [@fredpointzero](https://internals.rust-lang.org/u/fredpointzero)\
**Post date:** [August 29, 2019, 1:58pm UTC](https://internals.rust-lang.org/t/pre-rfc-variadic-tuple/10878/20 "2019-08-29T13:58:21Z")

</div>

I am not fan of `input: (i: ..#T)` because it is using two identifiers for the same variable.

I would say that both of these syntaxes are possible: `input: (..#T)` and `(..#input): (..#T)`. You will have to choose which one is more convenient for the implementation.

Some examples:

```rust
fn double<(..#T)>((..#input): (..#T)) -> (..#T)
	where ..#(T: Add), {
    (..#(input + input))
}

fn only_tuple_to_string<(..#T)>(input: (..#T)) -> String {
   format!("{}", input)
}

fn recursive<Head, (..#T)>((h, ..#tail): (..#T)) -> (..#T) {
    println!("{}", h);
    recursive((..#tail));
}
fn recursive<()>((): ()) { }

```

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