# Pre-RFC: #\[repr(rust)\] variadic functions

**URL:** <https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920>\
**Category:** language design\
**Created:** [March 2, 2020, 2:51pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920 "2020-03-02T14:51:31Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 2, 2020, 2:51pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/1 "2020-03-02T14:51:31Z")

</div>

I have heard that there is a general sentiment that rust doesn't need or shouldn't have variadic functions because the builder pattern is so good. While I must admit that the builder pattern is very good, I still think that there are some use cases for variadic functions.

* * *

## General Syntax:

function declarations:

```rust
fn sum_all(start: usize, items: ...usize) -> usize;

```

use of functions:

```rust
let rest = [4, 6, 9];
sum_all(0, 1, 2, rest...) // == 21

```

## Meaning:

A variadic function can be called with 0 or more arguments. The type is some type that implements `Iterator<item = T>` for a declaration `...T`.

A combination of individual and slice arguments are allowed. They will be iterated over in left to right order for each item. Effectively like `iter::once().concat(iter::once()).concat(slice.into_iter())`.

## Traits:

Such functions would be allowed in traits but would not have to be specified as a type parameter.

### Alternatives:

1. Do nothing, we can currently specify something very close to this in another way: ie the builder pattern.
2. Do not allow the joining of both individual items and other types of iterators. This is a smaller feature but I think it doesn't have enough weight behind it to be worth the effort.

---

<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:** [March 2, 2020, 3:00pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/2 "2020-03-02T15:00:38Z")

</div>

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:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 2, 2020, 3:17pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/3 "2020-03-02T15:17:50Z")

</div>

Do you mean generic over a Trait or literally any type?

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [March 2, 2020, 3:31pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/4 "2020-03-02T15:31:48Z")

</div>

I'm not sure what you're getting at with this question, but I guess the answer is "both"? AFAIK all useful variadic generic code would eventually need a trait bound to show up somewhere, but for the feature to scale to non-trivial examples there's also plenty of intermediate steps that would need to work on literally any types, like turning T1, T2, ... into an N-tuple and then later taking the Xth element of that tuple.

---

<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:** [March 2, 2020, 4:29pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/5 "2020-03-02T16:29:20Z")

</div>

Any type, not quite known at compile time. Things like `printf`. Args for `"%d %f %s"` are all different, so `...usize` or `...T` doesn't cut it.

---

<div class="post-metadata">

**Author:** ![gbutler](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gbutler/32/3670_2.png) [@gbutler](https://internals.rust-lang.org/u/gbutler)\
**Post date:** [March 2, 2020, 5:27pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/6 "2020-03-02T17:27:02Z")

</div>

I would think the "printf" type of problem is best/easily solved by using a `FormatMe` trait and passing an array/slice/etc `dyn FormatMe` items. Something like:

```rust
fn printf_like_function( formatString: &str, args : (dyn FormatMe)[] ) { ... }

```

Or perhaps it would need to be `Box<FormatMe>[]` or some-such. Is there something besides this sort of thing where something else would be needed/appropriate?

EDIT: Changed hypothetical trait name to ensure it is understood as not something that already exists necessarily.

EDIT 2: The reason I believe something like this is sufficient, is that, it is highly run-time dependent and so, I would think, that allocation overhead is probably not high on the list due to the inherent inefficiency.

I guess if, you wanted compile-time expansion and dispatch based on the compile-time types, then you'd be looking at something like the [Generic/Variadic Tuples proposal RFC](https://github.com/memoryleak47/variadic-generics/blob/master/0000-variadic-generics.md)

---

<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:** [March 2, 2020, 5:53pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/7 "2020-03-02T17:53:50Z")

</div>

Note: this is exactly how the `write` macro works (as well as all macros like it, ex. `println`)

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [March 2, 2020, 6:09pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/8 "2020-03-02T18:09:06Z")

</div>

How would the compiler be able to check the format string at compile time if it was a regular function argument (as opposed to the current situation, which is that it's passed to a compiler-defined macro)?

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 2, 2020, 10:05pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/9 "2020-03-02T22:05:18Z")

</div>

I see. So a lot of work would need to be done to be able to support this. Since it isn't a good idea to just box the trait object.

Would an intermediate solutions using only concrete types be possible as an in between step? That way we can implement some now and the rest later.

Users could then use boxing if they want ~~or something like the [auto\_enums](https://docs.rs/auto_enums/0.7.1/auto_enums/).~~

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [March 2, 2020, 11:08pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/10 "2020-03-02T23:08:48Z")

</div>

What does “using only concrete types” mean in this context? Any use of generics (variadic or otherwise) must provide concrete types somehow.

Note that we’ve always had variadic macros like vec! and print!, so it’s hard to see what subset of variadic generics could provide any new functionality. In fact, AFAIK the only significant benefit of “proper” variadic generics over macros is additional type safety, so there’s not even much design space to look for subsets in.

Also, the moment you do any kind of runtime indirection like boxing, you’re erasing types and are back to things we already have today like arrays/slices of trait objects.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 2, 2020, 11:25pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/11 "2020-03-02T23:25:51Z")

</div>

I mean that the type in the function signature would only be able to be a concrete type.

What I meant by boxing was that even with the above restriction, it would still be possible to use type objects using `Box<dyn T>`.

I guess there thus another possible alternative: a macro `variadic!`. Which concerts its arguments into a chain of iterators with the `...` meaning use "iter" instead of "once" .

---

<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:** [March 3, 2020, 12:17am UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/12 "2020-03-03T00:17:42Z")

</div>

The "uniform variadic" case is handled almost entirely by `for<N: usize> [T; N]`. (Sure, const generics are a ways off, but so would a variadics implementation.) For a literal list of arguments, this is pretty much how the variadic would be implemented.

The part that isn't covered by taking an array is the spread operator. And those are served by taking a `impl [Into]Iterator<Item = T>` with a `chain!` or `list!` macro to sugar the chaining.

(I assume the presence of `[T; N]: IntoIterator<Item=T>`.)

[Here's a draft of the two macros for sugaring calls to a function taking `impl [Into]Iterator`](https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=8908f2a33481fdd4b27d29a5531c7b2b):

```rust
macro_rules! ichain {
    ($front:expr $(,)?) => { IntoIterator::into_iter($front) };
    ($front:expr $(, $($rest:expr),* $(,)?)?) => {
        itertools::chain($front, ichain!($($($rest),*)?))
    };
}

macro_rules! isplat {
    (...$front:expr $(,)?) => { IntoIterator::into_iter($front) };
    (...$front:expr, $($rest:tt)*) => {
        itertools::chain($front, isplat!($($rest)*))
    };
    ($front:expr $(,)?) => { IntoIterator::into_iter($front) };
    ($front:expr, $($rest:tt)*) => {
        itertools::chain(Some($front), isplat!($($rest)*))
    }
}

```

`ichain` at least could probably be added to `itertools`.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 3, 2020, 1:55am UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/13 "2020-03-03T01:55:02Z")

</div>

I think that the iterator based solution is better since it would support both the spread operator and using multiple spread operators.

It does mean that direct indexing would not be supported. But I think that usefulness of joining multiple sources outweighs that.

---

<div class="post-metadata">

**Author:** ![storyfeet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/storyfeet/32/4461_2.png) [@storyfeet](https://internals.rust-lang.org/u/storyfeet)\
**Post date:** [March 3, 2020, 9:56am UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/14 "2020-03-03T09:56:53Z")

</div>

In all cases where a variadic function goes into what is basically an iterator there is no need to make this part of the function call, just a syntactic sugar for constructing another iterator

```rust
    iter![1,2,3,rest...]
   // where rest is IntoIterator perhaps.
   // or even
   iter![1,2,3,it1...,12,13,it2...,somevar]

```

I realize creating a macro that works over the second one would have a fair few challenges.

I guess at the defining end

```rust
    fn dothing(a:i32, b:String...){}

```

Could sugar to

```rust
    fn dothing<T:IntoIterator<item=String>(a:i32,b:T){}

```

It's just sugar, but IntoIterator is pretty core to Rust anyhow.

## OTOH:

If the arguments are of different types Then the only way to handle that typesafe would be default value args

---

<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:** [March 3, 2020, 9:57am UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/15 "2020-03-03T09:57:35Z")

</div>

> [@Ixrec](#):
>
> but for the feature to scale to non-trivial examples there's also plenty of intermediate steps that would need to work on literally any types, like turning T1, T2, ... into an N-tuple and then later taking the Xth element of that tuple.

Yeah.

Also, there's a lot of things you can do in eg D that don't work with a simple trait solver. Eg writing react-style DOM components for a web framework, with the components represented as structs:

```D
struct Button {
  DomNode!"div" button;
  Action click;
  @prop string innerText = "Click me!";
  @callback void onClick(MouseEvent event) {
    this.emit(click);
  }
}

struct App {
  DomNode!Button button;
  @connect!"button.click" void click() {
    printfln( "Hello world!" );
  }
}

mixin MyWasmDomFramework!App;

```

I'm not saying the pseudocode above is good or desirable.

But it's expressive, in a way that can't be done with typeless macros and trait arithmetic alone.

EDIT: Actually, I'm realizing [the Yew framework](https://github.com/yewstack/yew/releases/tag/0.13.0) does exactly that, so this is a bad example. Not sure what a better example of first-class types used for actual production work would look like.

---

<div class="post-metadata">

**Author:** ![jjpe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jjpe/32/9779_2.png) [@jjpe](https://internals.rust-lang.org/u/jjpe)\
**Post date:** [March 3, 2020, 1:15pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/16 "2020-03-03T13:15:23Z")

</div>

> [@storyfeet](#):
>
> In all cases where a variadic function goes into what is basically an iterator there is no need to make this part of the function call, just a syntactic sugar for constructing another iterator

While de sugaring to Iterators makes sense in principle, using iterators often enough involves heap allocation, and it would be a real waste to have to allocate just to use variadic arguments.

---

<div class="post-metadata">

**Author:** ![storyfeet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/storyfeet/32/4461_2.png) [@storyfeet](https://internals.rust-lang.org/u/storyfeet)\
**Post date:** [March 3, 2020, 2:12pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/17 "2020-03-03T14:12:02Z")

</div>

So is the suggestion that "rest" from the original post would have to be fixed size? to be able to use it, and the receiver would get a slice of that?

In every version of variadics I've come across before, it basically gets thrown into an array/vec of some kind, and the function only exists once.

This version seems to be Generic, and would exist for every number of args it is called with?

---

<div class="post-metadata">

**Author:** ![jjpe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jjpe/32/9779_2.png) [@jjpe](https://internals.rust-lang.org/u/jjpe)\
**Post date:** [March 3, 2020, 2:30pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/18 "2020-03-03T14:30:41Z")

</div>

I'm not sure this idea would ultimately work, but since the number of variadic items and their types are known at compile time, then in principle they can be allocated much like any other argument to regular fns. One place where that gets complicated is that there are multiple calling conventions, and any fn variadics feature that gets implemented has to work with all of them.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 3, 2020, 2:53pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/19 "2020-03-03T14:53:08Z")

</div>

What do you mean by "iterators often enough uses heap allocation". I don't see any `Box<T>` in any of `std::iter::Once`, `std::iter::Empty`, `std::iter::Chain`, or the `IntoIterator` implementations for `[]`. Since, I think that these would be the most common building steps I don't see where you claim comes from.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 3, 2020, 2:54pm UTC](https://internals.rust-lang.org/t/pre-rfc-repr-rust-variadic-functions/11920/20 "2020-03-03T14:54:21Z")

</div>

It is sort of generic, but the benefit of using iterators over a slice/vec solution is that there is no need to copy the elements to the vec just for the function (which it probably worse than a heap allocation anyway).

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