# Variadic Generics

**URL:** <https://forums.swift.org/t/variadic-generics/54511>\
**Category:** Pitches\
**Tags:** generics\
**Created:** [January 8, 2022, 5:38am UTC](https://forums.swift.org/t/variadic-generics/54511 "2022-01-08T05:38:55Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![codafi](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/codafi/32/791_2.png) [@codafi](https://forums.swift.org/u/codafi)\
**Post date:** [January 8, 2022, 5:38am UTC](https://forums.swift.org/t/variadic-generics/54511/1 "2022-01-08T05:38:56Z")

</div>

Hello Swift Evolution,

I'm pleased to bring you a refined copy of the variadic generics proposal, which was first pitched [in this thread](https://forums.swift.org/t/pitching-the-start-of-variadic-generics/51467).

The proposal text is available inline and [online](https://github.com/apple/swift-evolution/pull/1510).

I look forward to your feedback and questions.

* * *

# Variadic Generics

- Proposal: SE-NNNN
- Authors: [Robert Widmann](https://github.com/codafi)
- Review Manager: TBD
- Status: **Awaiting implementation**

## Introduction

Functions that take a variable number of arguments have proven to be an effective tool in Swift. Up to now, these functions could only accept a single type of argument. Authors have worked around this restriction by using less specific types like `Any` or by creating lots of overloaded boilerplate code at each argument arity.

Generic programming provides an effective answer to these challenges. This proposal seeks to unify Swift’s generic programming capabilities with its variable-arity programming features by adding _variadic generics_ to Swift.

## Motivation

Functions and aggregate types in Swift currently require a fixed number of generic arguments. To support functions that need to take an arbitrary number of arguments of any type, Swift currently requires erasing all the types involved. A prime example of this kind of function is `print`, which is declared with the following signature in the Swift standard library:

```swift
`func print(_ items: Any..., separator: String = " ", terminator: String = "\n")`

```

The `print` function uses a number of runtime tricks to inspect the type of each argument in the pack of existential `items` and dispatch to recover the appropriate description. But we also have many situations where the user wants to write a type-safe, generic, variadic function where the types of the arguments _cannot_ be erased in this manner.

SwiftUI’s primary result builder is a type called `ViewBuilder`. Today, `ViewBuilder` is artificially constrained to accept between 0 and 10 sub- `View` elements of differing types. What’s more, for each given arity, [a fresh declaration of buildBlock must be given](https://developer.apple.com/documentation/swiftui/viewbuilder/buildblock()), which leads to an explosion in the amount of boilerplate necessary to build the strongly-typed API that such a library desires. What would be ideal is if the Swift language provided a built-in way to express variadic generic functions. For our SwiftUI example above, we would like to write one and only one `buildBlock` function.

```swift
extension ViewBuilder {
    public static func buildBlock<V...>(views: V...) -> (V...) 
      where V: View
    {
        return views
    }
}

```

Finally, tuples have always held a special place in the Swift language, but working with arbitrary tuples remains a challenge today. In particular, there is no way to extend tuples, and so clients like the Swift Standard Library must take a similarly boilerplate-heavy approach and define special overloads at each arity for the comparison operators. There, the Standard Library chooses to artificially limit its overload set to tuples of length between 2 and 7, with each additional overload placing ever more strain on the type checker. Of particular note: This proposal lays the ground work for non-nominal conformances, but syntax for such conformances are **out of scope**.

## Proposed solution

We propose the addition of _generic parameter packs_ to Swift’s generics. These packs enable types and functions to declare that they accept a variable number and type of argument:

```swift
// 'max' accepts a pack of 0 or more Comparable 'T's
func max<T...>(_ xs: T...) -> T? where T: Comparable { /**/ }

// Tuple<T, U, V, ...> accepts a pack of element types
struct Tuple<Elements...> { /**/ }

```

To support the ability to store and return parameter packs, we propose the addition of _pack expansion_ types to Swift.

```swift
// The return type of this function '(T...)' is a pack expansion. It lets you
// gather variadic arguments together into a generic tuple-like value 
//
// let (s, i, d) = tuple("Hi", 42, 3.14) // : (String, Int, Double)
// let s = tuple("Hi") // : String
// _ = tuple() // ()
func tuple<T...>(_ xs: T...) -> (T...) { return xs } 

// You can have stored properties with a pack expansion as a type
struct Tuple<Elements...> { 
  var elements: (Elements...)
  init(elements: Elements...) { self.elements = elements }
}

```

## Detailed design

### Variadic Generic Parameters

Variadic generic parameter declarations are formed from “plain” generic parameter declarations plus the addition of trailing triple dots as in `func tuple<Elements...>`. Similarly, a type may declare a variadic generic parameter `struct Tuple<T...>`. A function may have any number of variadic generic parameters. Types, by contrast, support only one variadic generic parameter because of a lack of delimiter when instantiating them

```swift
func double<Ts..., Us...>(ts: Ts..., us: Us...) { /**/ } // ok

```

```swift
struct Broken<T..., U...> { /**/ }
typealias Bar = Broken<String, Int, Void> // Which types are bound to T... and U...?

```

### **Generic Parameter Packs**

Swift already has a syntax for variadic parameters in functions: `xs: T...`, as well as a number of rules around variadic applies that are already semantically well-formed. We choose to overload the syntax of variadic parameters to inherit this behavior, but also to show by extension that the semantics of variadic generic parameters are no different than those of monomorphic variadic parameters.

There is one peculiarity of this choice, though. Today, the interface type of `xs: T...` is sugar that produces an array type. This allows the user to reason about variadic parameters as a high-level container type. Parameters of variadic generic type will similarly implicitly construct a container type. However, instead of an array type, variadic generic parameters will be a new kind of container: _packs_. One can read the parameter in the following function as “`elements` is a pack of Ts”

```swift
func tuple<Ts...>(_ elements: Ts...) {}

```

The type parameter `Ts` is the “pattern type” of the constituent elements of the pack. It need not solely be a reference to a variadic generic parameter. The following demonstrates more advanced usages of pattern types in packs:

```swift
// This function: 
// - Takes a variadic sequence of (possibly-distinct) arrays of optional values
// - Removes the optional values from each one
// - Returns a pack with arrays sans `nil` elements.
func flattenAll<Ts...>(_ seqs: [Ts?]...) -> ([Ts]...) { 
  return seqs.map { $0.compactMap { $0 } }
}

```

### **Pack Expansions**

In order to support parameter packs in the return position of functions and as stored properties, we will need to introduce new syntax. At the type level, a parameter pack is nothing more than a tuple-like value with its elements and arity presented abstractly. Swift already has a natural space in its tuple syntax for just this operation: `(T...)` - read as the “pack expansion of `T`”. As the name implies, the type of the elements of `(T...)` are precisely the types of the elements of the pack used to construct `T...` when the function is called. Put another way, `(T...)` “unfolds” to become the (tuple) type of the elements provided to its parent variadic generic function. Returning to the variadic identity function from before:

```swift
func tuple<T...>(_ xs: T...) -> (T...) {
  return xs
}

tuple() // xs: Void
tuple(42) // xs: (Int) = Int
tuple(42, "Hello") // xs: (Int, String)

```

This is an extremely powerful typing rule, as it allows for the output of a function to observe the arity of its inputs - a form of dependent typing.

One other thing to observe about this example is that we do not require any special syntax to convert an input parameter pack to an output expansion. Because we take the view that the pack itself is a scalar object, there is no need to present a user-visible syntax to “splat” its elements. We simply forward the pack on, or transform it - by analogy with existing variadic parameters.

### **Iteration**

Going further, we can extend existing language constructs to support values with variadic types to enable a much more fluid syntax. Consider a slightly modified typesafe variadic version of `print`:

```swift
func printTypes<Args...>(_ items: Args...) {
  for (item: Args) in items {
    print(type(of: item), item)
  }
}

```

This proposed syntax uses Swift’s existing for-in loop construct to enable iteration over a pack. This shows how we can manipulate individual elements of the parameter pack one-by-one and can be accomplished with a builtin conformance of packs to `Sequence`.

Simultaneous operations on every element of a pack are also extremely important to have as language primitives. To support this, pack types will come with a “magic map” operation that functions identically to [its cousin for Swift Sequences](https://developer.apple.com/documentation/swift/sequence/3018373-map) - only this time it transforms the elements of a pack. A hypothetical internalization of this function is

```swift
extension<T...> (T...) {
  public func map<U...>(_ transform: (T) throws -> U) rethrows -> (U...) { /**/ }
}

```

### **Forwarding**

Implementations of variadics inevitably run into the problem of how to send one pack of arguments to another function that accepts a parameter pack. This is usually achieved via an operation called “splat” or “explode”, and one can think of it as taking a pack, breaking it down into its component parts, then calling the function. This usually involves special syntax like `*` in Ruby and Python, or C++‘s trailing `...` syntax (read as “pack out”). Since this proposal takes the tact that packs are values in their own right, we see no need for additional syntax. Therefore, we propose the removal of the restriction on passing variadic arguments to variadic parameters.

```swift
func forward<T...>(_ xs: T...) { return onwards(xs) }
func onwards<T...>(_ xs: T...) { /**/ }

```

A variadic argument is said to “saturate” a variadic parameter which means you cannot provide additional arguments before or after forwarding a variadic argument:

```swift
func forward<T...>(_ xs: T...) { 
  onwards(xs, "oops") // error: Too many arguments to 'onwards'!
  onwards("oops", xs) // error: Too many arguments to 'onwards'!
}
func onwards<T...>(_ xs: T...) { /**/ }

```

As a historical note, Swift already has the ability to forward (plain) variadic parameters, the user just cannot spell it. Internally, the implementation of compiler-provided overrides of variadic initializers (among other synthesized language elements) produces a variadic-to-variadic conversion on your behalf.

At the type level, it is also useful to be able to forward a pack of arguments to another pack of arguments. But it is _also_ useful to forward the pack of elements as a single tuple type. To support both of these behaviors, a pack expansion type `T...` appearing bound as a generic parameter will act to forward any expanded elements.

```swift
struct Forward<T...> {}
typealias Onwards<T...> = Forward<T...>

// Onwards<Int, String, Void> = Forward<Int, String, Void>

```

While a pack expansion type appearing parenthesized in this same position will act to bind a single tuple type after it has been expanded

```swift
struct Forward<T...> {}
typealias Onwards<T...> = Forward<(T...)>

// Onwards<Int, String, Void> = Forward<(Int, String, Void)>

```

### **All Together Now**

Using all of these concepts, we present a generalization of the standard library’s `zip` function to an arbitrary number and kind of sequences:

```swift
public func zip<Sequences...>(_ seqs: Sequences...) -> ZipSequence<Sequences...> 
  where Sequences: Sequence
{
    return ZipSequence(seqs)
}

public struct ZipSequence<Sequences...>: Sequence
  where Sequences: Sequence 
{

  private let seqs: (Sequences...)
  
  public init(_ seqs: Sequences...) {
      self.seqs = seqs  
  }
  
  public func makeIterator() -> Self.Iterator {
    return Self.Iterator(self.sequences)
  }
  
  public struct Iterator : IteratorProtocol {
    private enum Stop { case iterating }
    
    public typealias Element = (Sequences.Element...)
    
    private var reachedEnd = false
    var iterators: (Sequences.Iterator...)

    init(_ iterators: Sequences...) {
      self.iterators = iterators.map { $0.makeIterator() }
    }

    public mutating func next() -> Element? {
      if reachedEnd { return nil }

      guard 
        let values = try? iterators.map({ 
          guard let next = $0.next() else { throw Stop.iterating } 
          return next
        })
      else {
        reachedEnd = true
        return nil
      }
      return values
    }
  }
}

```

### Semantic Constraints

- A pack expansion that does not involve a variadic generic parameter is ill-formed outside the body of a function or closure

```swift
typealias Nope = (Int...)
typealias Nope<Again> = (Again...)

func nope<T...>(_ xs: T...) -> (Int...) {}

struct Nope {
  var xs: (Int...)
}

func ok<T...>(_ xs: T...) {
  let zeroes: (Int...) = xs.map { 0 }
  // There's not much you can do with this value...
  
  struct NestedNope {
    var zeroes: (Int...) // Nope!
  }
}

```

- Pack expansion types may not appear in associated type requirements for protocols. They may, however, appear in type witnesses themselves

```swift
protocol Nope { associatedtype (Ts...) }

```

- Parameters of pack type cannot be `inout`, in keeping with existing language restrictions

```swift
func foo<T...>(_ xs: inout T...) {} // 'inout' must not be used on variadic parameters

// This doesn't work either!
func foo<T>(_ xs: inout T...) {} // 'inout' must not be used on variadic parameters`

```

- Pack expansion types may not appear in inheritance clauses

```swift
protocol Nope : (T...) {}
class Nope<Again...> : (Again...) {}

```

- A pack expansion type may not appear in the position that would otherwise bind a non-variadic generic parameter

```swift
struct Singleton<T> {}
typealias PackOf<Ts...> = Singleton<Ts...> // Oops!

```

- The arity of an argument pack must remain consistent when variadic generic types are mentioned in multiple parameters

```swift
// 'first' mentions T... and U..., so it must have the
// same arity as 'second' which mentions 'T...' and
// the same arity as 'third' which mentions 'U...'
func foo<T..., U...>(
  first: [T: U]...,
  second: T...,
  third: U...
) where T: Hashable

foo(first: [String:Void](), second: "K", third: ()) // ok
foo(first: [String:Void](), second: "K", "L", third: ()) // nope!

```

- Equality constraints between variadic generic parameters must similarly only involve other variadic generic parameters.

```swift
func foo<T..., U>() where T == U // nope!

```

- Equality constraints that would concretize a pack expansion type are banned.

```swift
func foo<T..., U>() where (T...) == (Int, String, Void) // nope! 

```

### Grammatical Ambiguities

The use of `...` in parameter lists to introduce a generic variadic parameter introduced a grammatical ambiguity with the use of `...` to indicate a (non-generic) variadic parameter. The ambiguity can arise when forming a pack expansion type. For example:

```swift
struct X<U...> { }

struct Ambiguity<T...> {
  struct Inner<U...> {
    typealias A = X<(T...) -> U...>
  }
}

```

Here, the `...` within the function type `(T...) -> U` could mean one of two things:

- The `...` defines a (non-generic) variadic parameter, so for each element `Ti` in the parameter pack, the function type has a single (non-generic) variadic parameter of type `Ti`, i.e., `(Ti...) -> U`. So, `Ambiguity<String, Character>.Inner<Float, Double>.A` would be equivalent to `X<(String...) -> Float, (Character...) -> Double>`.
- The `...` expands the parameter pack `T` into individual parameters for the function type, and no variadic parameters remain after expansion. Only `U` is expanded by the outer `...`. Therefore, `Ambiguity<String, Character>.Inner<Float, Double>.A` would be equivalent to `X<(String, Character) -> Float, (String, Character) -> Double>`.

If we take the first meaning, then it is hard to expand a parameter pack into separate function parameter types, which is necessary when accepting a function of arbitrary arity, e.g.,

```swift
func forwardWithABang<T..., R>(_ args: T?..., body: (T...) -> R) -> R {
  body(args.map { $0! })
}

```

Therefore, we propose that the `...` in a function type be interpreted as a pack expansion type when the pattern of that type (e.g., the `T` in `...`) involves a parameter pack that has not already been expanded. This corresponds with the second meaning above. It is source-compatible because the “pattern” for existing code will never contain a parameter pack.

With this scheme, it is still possible to write code that produces the first meaning, by abstracting the creation of the function type into a `typealias` that does not involve any parameter packs:

```swift
struct X<U...> { }

struct AmbiguityWithFirstMeaning<T...> {
  struct Inner<U...> {
    typealias VariadicFn<V, R> = (V...) -> R
    typealias A = X<VariadicFn<T, U>...>
  }
}

```

Note that this ambiguity resolution rule relies on the ability to determine which names within a type refer to parameter packs. Within this proposal, only generic parameters can be parameter packs and occur within a function type, so normal (unqualified) name lookup can be used to perform disambiguation fairly early. However, there are a number of potential extensions that would make this ambiguity resolution harder. For example, if associated types could be parameter packs, then one would have to reason about member type references (e.g., `A.P`) as potentially being parameter packs.

## Source compatibility

The majority of the elements of this proposal are additive. However, the use of triple dots `...` in the type grammar has the potential to conflict with the existing parsing of user-defined operators. Take this stream of tokens:

```swift
T...>foo

```

This has the potential to be parsed as an operator `...>` applied to two arguments as in

```swift
(T) ...> (foo)

```

or as a fragment of a generic parameter as in

```swift
/*HiddenType<*/T...> foo

```

To break this ambiguity, in function declarations and type expressions we require that the dots `...` _always_ bind to their preceding generic parameter, if any.

We strongly suspect there are little to no libraries taking advantage of this kind of operator overloading, but we wish to call it out as it creates a new reserved class of expression in the grammar.

## Effect on ABI stability

This proposal is additive, and has no affect on the existing ABI of libraries.

## Effect on API resilience

This proposal is additive, and has no affect on the existing API of libraries.

## Alternatives considered

There are a number of alternative formulations of variadics that have been implemented in many different languages. The approach detailed here is particularly inspired by the work of [Felleisen, Strickland, and Tobin-Hochstadt](https://link.springer.com/content/pdf/10.1007/978-3-642-00590-9_3.pdf) who presented the bones of the inference algorithm needed to implement the type system extensions.

### Explicit Syntax for Pack Expansion in Expressions

“Magic map” is a way to sidestep this particular requirement of C++‘s implementation of variadics. There, `...` in postfix position in an expression directs the compiler to syntactically expand any packs in the preceding expression and optionally [“fold” it around an operator](https://en.cppreference.com/w/cpp/language/fold). Explicit pack expansion syntax has a number of upsides, but it also complicates the forwarding story presented above. Most glaringly, Swift already has a meaning for postfix `...` in expression position with [one-sided ranges](https://github.com/apple/swift-evolution/blob/main/proposals/0172-one-sided-ranges.md).

### Alternative Syntax for Variadic Generic Parameters/Expansions

We chose `...` by analogy with Swift’s existing syntax for variadic parameters. However, there’s no reason we cannot pick a different syntax, especially one that does not conflict with one-sided ranges. Suggestions from [the first pitch thread](https://forums.swift.org/t/pitching-the-start-of-variadic-generics/51467) include: `T*`, `*T`, `variadic T`, `pack T`, `T[]`, and many more.

## Future directions

### Non-Nominal Conformances

We do not explicitly propose a syntax for non-nominal extensions and protocol conformances involving pack types. In concert with [parameterized extensions](https://github.com/apple/swift/blob/main/docs/GenericsManifesto.md#parameterized-extensions), however, there is a natural syntax:

```swift
extension<T...> (T...) {
  public var count: Int { /**/ }
}

extension<T...> (T...): Equatable where T: Equatable {
  public static func == (lhs: Self, rhs: Self) -> Bool { 
    for (l, r) in zip(lhs, rhs) {
      guard l == r else { return false }
    }
    return true
  }
}

extension<T...> (T...): Comparable where T: Comparable {
  public static func < (lhs: Self, rhs: Self) -> Bool { 
    guard lhs.count > 0 else { return true } 
    
    for (l, r) in zip(lhs, rhs) {
      guard l < r else { return false }
    }
    return true
  }
}

```

```swift
import SwiftUI

extension <T...> (T...): View where T: View {
    var body: some View { /**/ }
}

```

### Additional Structural Pack Operations

A natural extension to this feature set is the ability to concatenate and destructure compound pack expansion types and their corresponding values. To support the former, a magical `append` function could be added that looks as follows:

```swift
extension<T...> (T...) {
  public func append<U...>(_ xs: U...) -> (T..., U...) { /*poof!*/ }
}

```

To support the latter, the ability to abstract over multiple values in patterns is needed:

```swift
let (first, remaining...) = ("A", "B", "C").append(1, 2, 3)
// first: String, last: (String, String, Int, Int, Int)

```

It would also make sense to support the mixing of pack expansions with normal tuple element types as in

```swift
func atLeastTwo<T, U, V...>(_ x: T, _ y: U, v: V...) -> (T, U, V...) {
  return (x, y).append(v)
}

let (x, y, rest...) = atLeastTwo("Hello", 42) // rest: ()

```

### Explicit Arity Constraints

We could allow users to reason explicitly about the arity of packs. In particular, they could present inequalities to the type checker and those could, in turn, restrict the types of packs allowed at a particular apply. A purely illustrative example is:

```swift
extension <T...> (T...) where (T...).count >= 4 {}

```

---

<div class="post-metadata">

**Author:** ![SwiftUI](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/swiftui/32/24361_2.png) [@SwiftUI](https://forums.swift.org/u/SwiftUI)\
**Post date:** [January 8, 2022, 12:36pm UTC](https://forums.swift.org/t/variadic-generics/54511/2 "2022-01-08T12:36:58Z")

</div>

Could you clarify why the pack of VG types can't be `inout`?

Furthermore, which means that all future `consuming/ref/inout` type values couldn't be passed to VG parameters?

---

<div class="post-metadata">

**Author:** ![Paulo\_Faria](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/paulo_faria/32/20351_2.png) [@Paulo\_Faria](https://forums.swift.org/u/Paulo_Faria)\
**Post date:** [January 8, 2022, 12:48pm UTC](https://forums.swift.org/t/variadic-generics/54511/3 "2022-01-08T12:48:31Z")

</div>

This looks great!

---

<div class="post-metadata">

**Author:** ![George](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/george/32/37757_2.png) [@George](https://forums.swift.org/u/George)\
**Post date:** [January 8, 2022, 3:29pm UTC](https://forums.swift.org/t/variadic-generics/54511/4 "2022-01-08T15:29:55Z")

</div>

First of all, thank you for pushing further on this! Everything seems well thought out and I find the new terminology very clear.

> [@codafi](#):
>
> Pack expansion types may not appear in associated type requirements for protocols. They may, however, appear in type witnesses themselves

Is this a pragmatic limitation or a design decision? My gut feeling is that protocols having associated packs might be a useful future direction, specifically for providing an improved form of `Codable`.

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [January 8, 2022, 3:47pm UTC](https://forums.swift.org/t/variadic-generics/54511/5 "2022-01-08T15:47:27Z")

</div>

> [@codafi](#):
>
> This proposed syntax uses Swift’s existing for-in loop construct to enable iteration over a pack. This shows how we can manipulate individual elements of the parameter pack one-by-one and can be accomplished with a builtin conformance of packs to `Sequence` .

Oh, and what would a pack’s `Element` type be?

---

<div class="post-metadata">

**Author:** ![George](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/george/32/37757_2.png) [@George](https://forums.swift.org/u/George)\
**Post date:** [January 8, 2022, 4:20pm UTC](https://forums.swift.org/t/variadic-generics/54511/6 "2022-01-08T16:20:10Z")

</div>

> [@codafi](#):
>
> ```swift
> // 'first' mentions T... and U..., so it must have the
> // same arity as 'second' which mentions 'T...' and
> // the same arity as 'third' which mentions 'U...'
> func foo<T..., U...>(
> first: [T: U]...,
> second: T...,
> third: U...
> ) where T: Hashable
> 
> ```

One additional clarification request, the example above seems to be the only one which has a non-trivial pack expansion. Could you elaborate a bit on what the underlying mechanism here is, is it just "any type expression which has the pack parameter in it"? For examples, users might want to define their own functions with signatures like the following (admittedly contrived) examples.

```swift
func getTypes<T...>(_ pack: T...) -> T.Type... { … }
func map<T...>(_ pack: T...) -> T.SomeAssociatedType... where T: SomeProtocol { … }
func wrap<T...>(_ pack: T...) -> SomeWrapperType<T>... { … }

```

Also, would it be possible to express relationships between packs?

```swift
struct Foo<A, B> 
where 
  A: SomeProtocol, B: SomeProtocol 
  A.SomeAssociatedType == B.SomeAssociatedType
{
}
func merge(a: A..., b: B...) -> Foo<A, B>...
where
  /// A and B satisfy Foo's requirements
{ … }

```

---

<div class="post-metadata">

**Author:** ![QuinceyMorris](https://avatars.discourse-cdn.com/v4/letter/q/d26b3c/32.png) [@QuinceyMorris](https://forums.swift.org/u/QuinceyMorris)\
**Post date:** [January 8, 2022, 5:50pm UTC](https://forums.swift.org/t/variadic-generics/54511/7 "2022-01-08T17:50:04Z")

</div>

A small comment on the proposal text:

It seems clear to me from the detailed description that the only viable "spelling" for generic type placeholder symbols is the singular form, not the plural. So, `T...`, not `Ts...`, or `Arg...`, not `Args...`. "Pluralizing" the symbol works especially badly in this:

```swift
  for (item: Args) in items {

```

For that reason, I'd suggest changing the proposal text to use the singular forms everywhere.

On the other hand, using a plural form in parameter/keyword symbols — `items:` — seems correct. However, I find it takes work to grasp that `xs` is intended to be the plural of `x`. It bothered me every time, not just the first time I encountered it.

I'd suggest changing the proposal text to use an actual word instead of `xs:`, such as `values:`.

These textual changes wouldn't affect what's being proposed, but would I think make it significantly easier to read.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [January 8, 2022, 6:02pm UTC](https://forums.swift.org/t/variadic-generics/54511/8 "2022-01-08T18:02:55Z")

</div>

Thanks for your continued work on this, @codafi!

I remain somewhat averse to the `...` spelling for reasons mentioned in the previous thread. Most concerning to me is:

> [@Pitching The Start of Variadic Generics](https://forums.swift.org/t/pitching-the-start-of-variadic-generics/51467/5):
>
> The bigger issue for me when it comes to the `...` spelling is how it pans out for generic types. From the body of the example `ZipSequence` type:
> 
> ```swift
> public init(_ seqs: Sequences...) {
> self.seqs = seqs  
> }
> 
> ```
> 
> The only way we can tell for sure that `Sequences` is a variadic type sequence rather than `seqs` being a variadic parameter is to inspect the generic signature where `Sequences` is declared. While this is not so much of an issue for functions (since the generic parameter will always be fairly local to its use), type members may be defined in a separate extension, which means they could be in a disparate part of the file, another file, or another module entirely.

IMO, although the `...` syntax is nice and terse, the potential breakdown of local reasoning ability is a good reason to prefer something else.

* * *

I don't know where exactly the Swift API design guidelines sit with regard to Swift evolution, but I think that as part of the variadic generics design we should settle on some conventions which could eventually be subsumed as part of the API guidelines. In particular, I am still bothered by the interchangeable use of plural and singular terminology for generic parameter packs. It looks like this proposal has _mostly_ settled on plural terminology (though we still have some `T`, `U` usages rather than `Ts` and `Us`), but IMO that becomes a bit problematic given:

> [@codafi](#):
>
> The type parameter `Ts` is the “pattern type” of the constituent elements of the pack.

because it means that the parameter name is used in contexts that refer to the aggregate pack (plural) as well as the _individual constituent pack types_. I think this makes for some confusing signatures such as:

> [@codafi](#):
>
> ```swift
> public struct ZipSequence<Sequences...>: Sequence
> where Sequences: Sequence 
> {
> 
> ```

Here, `Sequences: Sequence` is really saying "each constituent type of `Sequences` is itself a `Sequence`, but IMO a perfectly plausible reading of this is "the `Sequences` pack is a `Sequence` itself." This particular example is made even more confusing by the fact that the erroneous interpretation is in fact _true_, since the pack as a whole _does_ conform to `Sequence`.

This strangeness can also be seen in:

> [@codafi](#):
>
> ```swift
> func printTypes<Args...>(_ items: Args...) {
> for (item: Args) in items {
> print(type(of: item), item)
> }
> }
> 
> ```

The type of `item` is really a _single_ 'arg' from the `Args...` pack, but the use of the plural terminology reads as if `item` is itself some sort of aggregate type.

I'd really like it if we could have a design which allows for explicit differentiation between the singular usage and the aggregate usage of the variadic parameter names. In the previous pitch I came up with a somewhat verbose `forEach` syntax that would allow for the explicit introduction of the 'singular' name of a variadic parameter:

> [@Pitching The Start of Variadic Generics](https://forums.swift.org/t/pitching-the-start-of-variadic-generics/51467/5):
>
> ```swift
> func allPresent<Haystacks..., Needles...>(haystacks: Haystacks..., needles: Elements...) -> Bool
> where forEach(Haystack in Haystacks, Needle in Needles, Haystack == Set<Needle>)
> 
> ```

but I'd also be fine with some sort of syntax that indicates "we're really talking about an _arbitrary element_ of this pack, maybe something like:

```swift
public struct ZipSequence<Sequences...>: Sequence
  where Sequences[_]: Sequence 
{

```

ETA: @QuinceyMorris's suggestion of always preferring the _singular_ spelling for variadic generic parameters is also compelling to me, and wouldn't require the invention of new syntax to refer to a singular element. The bare name (e.g., `Arg`) would always refer to a singular element, and the aggregate would always be spelled with the trailing `...` (e.g., `Arg...`). That also agrees with the existing usage of `...` for variadic parameters, for which we write the _singular_ type name and use `...` to 'pluralize' it, e.g., `Int...`.

Regardless of which direction we choose, though, I think the proposal should take an opinionated stance on the 'right' way to design variadic generic signatures.

* * *

I'm also still wondering if we really need to introduce the new "generic parameter packs" to the language:

> [@Pitching The Start of Variadic Generics](https://forums.swift.org/t/pitching-the-start-of-variadic-generics/51467/22):
>
> Another thing I've been mulling over is whether we need to have a bright-line distinction between "type sequences" and "tuples". That is, if we add all the special operators ( `_countTypeSequence` , `_mapTypeSequence` , etc.), would it be sufficient to say that a generic parameter `T*` declares a type `T` which stands for a tuple of arbitrary arity? Then, we could have a tuple-splat operator for turning a `T` value into its constituent parts (for e.g. function application). This might also dovetail nicely with [`@expanded`](https://forums.swift.org/t/gsoc-shared-storage-for-property-wrappers-and-expanded-parameters/51355) to give us a way of expanding a variadic tuple into a parameter list, e.g.:
> 
> ```swift
> func variadic<Tuple*>(args: @expanded Tuple)
> // or
> func variadic<Tuple*>(args: #splat(Tuple))
> // or, maybe 'Tuple' means the tuple version of the 
> // type, and 'Tuple*' the splatted version
> func variadic<Tuple*>(args: Tuple*)
> 
> ```
> 
> all of these could indicate that `variadic` is callable as:
> 
> ```swift
> variadic("Hello", 1, 2.0)
> 
> ```
> 
> This could also imply (though it wouldn't _have_ to) that all the special type sequence operations would be applicable to fixed-size tuples as well:
> 
> ```swift
> for elt in ("Hello", 1, 2.0) {
> // elt is 'Any' here?
> }
> 
> ```

If we were to 'superpower' tuples, could we get away with not introducing an entirely new concept to the language? Is there a fundamental expressivity issue with tuples that prevents us from realizing everything we would want from variadic parameters?

* * *

Regarding the "only one variadic parameter in a generic type" rule, is this a restriction we want to lift eventually? If so, could we allow such types to be defined and rely on generic parameter inference to fill in each pack appropriately?

> [@Pitching The Start of Variadic Generics](https://forums.swift.org/t/pitching-the-start-of-variadic-generics/51467/36):
>
> However, we allow generic parameters to be inferred in many (most?) cases, so if multiple variadic parameters are allowed in `Zip` 's `init` it seems reasonable that we could write:
> 
> ```swift
> let z = Zip(xs: a, b, ys: c, d, e)
> 
> ```
> 
> And have the generic parameters to `Zip` inferred. Then we could worry about the syntax for explicit parameterization later.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [January 8, 2022, 6:22pm UTC](https://forums.swift.org/t/variadic-generics/54511/9 "2022-01-08T18:22:41Z")

</div>

A couple more questions:

1. What is the expected syntax around _empty_ parameter packs for functions. E.g.:

2. Similarly, what about empty parameter packs for types?

3. How do we want properties of generic parameter pack tuples to interact with the synthesized initializer? E.g.,

---

<div class="post-metadata">

**Author:** ![benrimmington](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/benrimmington/32/695_2.png) [@benrimmington](https://forums.swift.org/u/benrimmington)\
**Post date:** [January 8, 2022, 8:49pm UTC](https://forums.swift.org/t/variadic-generics/54511/10 "2022-01-08T20:49:17Z")

</div>

> [@codafi](#):
>
> The proposal text is available inline and [online](https://github.com/apple/swift-evolution/pull/1510).

Please could you add syntax highlighting to the pull request.

* * *

> [@codafi](#):
>
> A prime example of this kind of function is `print`, …

Would a type-safe `print` only avoid boxing the items as `Any`, but still need runtime checks for the `Custom[Debug]StringConvertible` and `TextOutputStreamable` conformances?

* * *

> [@codafi](#):
>
> ```swift
> // 'max' accepts a pack of 0 or more Comparable 'T's
> func max<T...>(_ xs: T...) -> T? where T: Comparable { /**/ }
> 
> ```

How would this (and the examples in _Future directions_) be able to compare across different types in the pack? The `<` and `==` operator functions have `Self` operands.

* * *

> [@codafi](#):
>
> Types, by contrast, support only one variadic generic parameter because of a lack of delimiter when instantiating them
> 
> ```swift
> struct Broken<T..., U...> { /**/ }
> typealias Bar = Broken<String, Int, Void> // Which types are bound to T... and U...?
> 
> ```

The semi-colon delimiter (`Broken<String; Int, Void>`) is probably available.

---

<div class="post-metadata">

**Author:** ![masters3d](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@masters3d](https://forums.swift.org/u/masters3d)\
**Post date:** [January 8, 2022, 9:14pm UTC](https://forums.swift.org/t/variadic-generics/54511/11 "2022-01-08T21:14:27Z")

</div>

> [@codafi](#):
>
> `struct X<U...> { }`

I am assuming that something like this will be allowed:

```swift

struct X <U…> {
    private let somePack: (U…)
    init ( someInput: (U…) ) { 
       somePack = someInput // is this the forwarding ?
    }
}

```

Are packs just heterogeneous tuples?

I am having trouble understanding how packs ( which can be heterogeneous ) are Iterable ( for loop into them).

> [@codafi](#):
>
> ```swift
> func printTypes<Args...>(_ items: Args...) {
> for (item: Args) in items {
> print(type(of: item), item)
> }
> }
> 
> ```

In the above example the Args’s type is potentially different. In todays code that would have to be Any.

---

<div class="post-metadata">

**Author:** ![Nobody1707](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nobody1707/32/2169_2.png) [@Nobody1707](https://forums.swift.org/u/Nobody1707)\
**Post date:** [January 8, 2022, 11:04pm UTC](https://forums.swift.org/t/variadic-generics/54511/12 "2022-01-08T23:04:02Z")

</div>

The type would be different for each argument in the pack, but each type would be known statically at compile time. I imagine it would be equivalent to writing out...

```swift
do {
    // obviously, there's no proposed syntax for getting the nth element of a pack
    // so this is just for exposition.
    let item = pack.0
    print(type(of: item), item)
}
do {
    let item = pack.1
    print(type(of: item), item)
}
// etc.

```

Until you've covered each item in the pack. Although the compiler would potentially do something more efficient than that.

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [January 9, 2022, 12:33am UTC](https://forums.swift.org/t/variadic-generics/54511/13 "2022-01-09T00:33:03Z")

</div>

This is great!

I’ve been looking forward to variadic generics for a long time, and I like the direction you’ve gone here.

I’m sure I’ll have more thoughts and questions after I’ve digested the proposal a bit, but for now I just want to ask about one of the listed restrictions:

> [@codafi](#):
>
> - Equality constraints that would concretize a pack expansion type are banned.
> 
> ```swift
> func foo<T..., U>() where (T...) == (Int, String, Void) // nope! 
> 
> ```

I think this could be useful, especially for constrained extensions:

```swift
struct Foo<T...> {
  // something
}

extension Foo where (T...) == (Int, String, Void) {
  // some particular things
}

```

---

<div class="post-metadata">

**Author:** ![1oo7](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/1oo7/32/17598_2.png) [@1oo7](https://forums.swift.org/u/1oo7)\
**Post date:** [January 9, 2022, 5:36am UTC](https://forums.swift.org/t/variadic-generics/54511/14 "2022-01-09T05:36:26Z")

</div>

I was just thinking about this, and boom yesterday someone made a proposal. The universe is funny like that!

Specifically, what I would like to do is something like this:

```swift
func foo<Root..., Value...>(keyPaths: KeyPath<Root, Value>...) { 
    func process<Root>(_ keyPath: KeyPath<Root, Int>) { ... }
    func process<Root>(_ keyPath: KeyPath<Root, String>) { ... }
    /// Gets called if value isn't `Int` or `String`.
    func process<Root, Value>(_ keyPath: KeyPath<Root, Value>) { ... } 
    for keyPath in keyPaths {
        process(keyPath)
    }
}

```

Can we update your proposal such that this would be handled, or would it be non-feasible?

---

<div class="post-metadata">

**Author:** ![1oo7](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/1oo7/32/17598_2.png) [@1oo7](https://forums.swift.org/u/1oo7)\
**Post date:** [January 9, 2022, 6:02am UTC](https://forums.swift.org/t/variadic-generics/54511/15 "2022-01-09T06:02:18Z")

</div>

You've discussed "packs" at length but not given an example of how a pack is declared in Swift. What is it exactly?

E.g.

```swift
struct Pack: Packable { ??? what goes in here ??? }

```

Questions about packs:

1. How is pack defined exactly?
2. How is a pack different from a collection exactly?
3. How can you programmatically access the individual members of a pack?
4. How does a pack interact with reflection and debugger introspection?
5. Why is it called a "pack" (a word that usually refers to a group of things of identical type to one another, like a pack of cards or a pack of wolves) as opposed to using a word that better reflects the fact that it can be a group of completely diverse types, such as "medley"?
6. If "pack" refers to the group of generic types in the generic params, then what refers to the type of the collection of various-typed objects in the function parameters...? (Are these also a pack, or still a collection?)
7. how do you deal with capture groups and packs?

E.g.:

```swift
func foo<T..., U...>(_ t: T..., u: U...) {
    let myClosure: () -> Void = { [t, u] in
        ...
    }
}

```

1. What types are captured `t` and `u` inside the closure? I.e. is `t` a "pack" or a "collection"?
2. Is `t` a copy of the original pack `t` or is it the same instance, just retained, because packs are reference types?
3. What happens if you `print(type(of: t))`?
4. What if some T's and U's are reference types and others are not... ?
5. Can **`weak`** modifier be applied to the capture group argument in a way that applies only to objects among the various things in `t` or `u`?
6. Does this proposal require any dynamic behaviors or can it rely purely on static behaviors as current generics do?

Please disregard if you've already discussed elsewhere how these "packs" deal with memory concerns when they contain some value types and some reference types.

> [@benrimmington](#):
>
> > [@codafi](#):
> >
> > Types, by contrast, support only one variadic generic parameter because of a lack of delimiter when instantiating them
> > 
> > > ```swift
> > > struct Broken<T..., U...> { /**/ }
> > > 
> > > ```
> > 
> > typealias Bar = Broken\<String, Int, Void\> // Which types are bound to T... and U...?
> > 
> > > ```swift
> > > 
> > > ```
> 
> The semi-colon delimiter ( `Broken<String; Int, Void>` ) is probably available.

How about just allow variadic generic parameters to have parameter labels, e.g.:

```swift
struct Broken<A: T..., B: U...>
typealias Bar = Broken<A: String, B: Int, Void> 

```

... in which case, the type of A is something like, `PackWrapper<T...>` and the type of B is `PackWrapper<U...>`. Thoughts?

---

<div class="post-metadata">

**Author:** ![technicated](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/technicated/32/5420_2.png) [@technicated](https://forums.swift.org/u/technicated)\
**Post date:** [January 9, 2022, 5:45pm UTC](https://forums.swift.org/t/variadic-generics/54511/16 "2022-01-09T17:45:42Z")

</div>

First things first, thank you very much for this updated proposal on the subject!

Then, what if we treat "packs" as `Collection`s, with a capital "C"? You can have all the benefits of `map` & co. (and even more, if we can / want to give them conformances to `BidirectionalCollection` and / or `RandomAccessCollection`), and moreover they can be blessed with a little compiler magic so that:

- in static contexts the compiler knows order and position of all the members, and maybe can allow direct access using (checked?) indexed or dot notation
- in dynamic / completely generic contexts you can rely on `Collection` operations to do all the necessary work

In this way you are not forced to immediately convert Variadic Generics to tuples, but can do so if needed, and you need not introduce a "special" `map` operation.

Speaking of `map`, I think the operation should take into account mutability: as currently defined you cannot, for example, invoke `Iterator.next()` because it is a mutating method. However, would we define the parameter to be `inout`, I'm not sure about `map` being the correct name (not sure about the relationship between `inout` and pure functions).

---

<div class="post-metadata">

**Author:** ![tevelee](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tevelee/32/9775_2.png) [@tevelee](https://forums.swift.org/u/tevelee)\
**Post date:** [January 9, 2022, 11:37pm UTC](https://forums.swift.org/t/variadic-generics/54511/17 "2022-01-09T23:37:34Z")

</div>

Thanks for actively working on this, @codafi! This is a long-awaited feature.  
A couple of comments:

> [@codafi](#):
>
> ```swift
> func max<T...>(_ xs: T...) -> T? where T: Comparable { /**/ }
> 
> ```

This example requires all Ts in the pack being the same type, as [Comparable has Self type requirement](https://developer.apple.com/documentation/swift/comparable/1538311), so this is not a case of variadic generics, but a regular generic function with a variadic parameter:

```swift
func max<T>(_ xs: T...) -> T? where T: Comparable

```

The variadic generic format would allow writing `max(“Hi”, 42, 3.14, Date())`, which technically satisfies the function signature (since all of String, Int, Double, and Date do conform to Comparable), but they’re all of different types, therefore the implementation of the function `max` is semantically impossible.  
Perhaps a better example would be to constraint T… to Numeric instead.

* * *

> [@codafi](#):
>
> `func tuple<T...>(_ xs: T...) -> (T...) { return xs }`

I also find the idea of pack expansions a bit problematic. Apart from the fact that it could produce single element tuples, makes the syntax `T...` ambiguous for the reader, because if refers to different concepts in each position. In the first position (between the angle brackets), it signals that this generic parameter is something that is not a concrete, single type, but a sequence of those. The second (in the parameter position) is the already existing variadic syntax. While the last tuple-like one refers to a concrete return type of an anonymous sequence of existential types. This mixture can become a source of confusion. I’d prefer if these 3 occasions were written differently, as they stand for different concepts. For example

```swift
func tuple<T*>(_ xs: T...) -> pack T // similar to some T and any T

```

---

<div class="post-metadata">

**Author:** ![fclout](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/fclout/32/36155_2.png) [@fclout](https://forums.swift.org/u/fclout)\
**Post date:** [January 10, 2022, 6:12am UTC](https://forums.swift.org/t/variadic-generics/54511/18 "2022-01-10T06:12:09Z")

</div>

I'm happy this is moving forward. I read the current proposal and came away with the following 3 questions:

* * *

It sounds like in `func buildBlock<V...>(views: V...) -> (V...) where V: View`, each `V` can be an independent type that conforms to `View` (all views don't need to be the same type). However, right at the start of the Proposed Solution section, we see the following example:

```swift
func max<T...>(_ xs: T...) -> T? where T: Comparable

```

which isn't workable if each `T` is allowed to be separate since `Comparable` can only compare `Self` objects.

It seems to me that `max` could be currently written as `func max<T>(_ xs: T...) -> T? where T: Comparable` (except that it would use monomorphic variadic parameters instead of the new parameter packs), so I'm guessing that the first interpretation is right and this example needs to be updated?

* * *

How do you explicitly specify the generic parameters of functions with multiple variadic generic parameter packs? In `double<Ts..., Us...>`, if I want a "function pointer" closure to `double` that has Ts=(Int, Int) and Us=(Double, Double), how do I spell that? `double<Int, Int, Double, Double>` is ambiguous for the same reasons that types are.

* * *

How does iteration work with protocols with associated types? Is `for (item: Args) in items` magic, given that `item: Args` is invalid typing as of the current Swift? (Are there interactions with SE-0335 and SE-0309?)

---

<div class="post-metadata">

**Author:** ![Zollerboy1](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/zollerboy1/32/12997_2.png) [@Zollerboy1](https://forums.swift.org/u/Zollerboy1)\
**Post date:** [January 10, 2022, 12:13pm UTC](https://forums.swift.org/t/variadic-generics/54511/19 "2022-01-10T12:13:11Z")

</div>

> [@fclout](#):
>
> How do you explicitly specify the generic parameters of functions with multiple variadic generic parameter packs? In `double<Ts..., Us...>` , if I want a "function pointer" closure to `double` that has Ts=(Int, Int) and Us=(Double, Double), how do I spell that? `double<Int, Int, Double, Double>` is ambiguous for the same reasons that types are.

You cannot do that even with normal generic functions.

If you want to reference a generic function you have to use either `as` or a type hint, e.g.:

```swift
func foo<T>(_ t: T) {}

let foo2 = foo<Int> // Error: Cannot explicitly specialize a generic function

let bar = foo as (Int) -> ()
// or
let baz: (Int) -> () = foo

```

However, this breaks down as well for functions with multiple generic parameter packs:

```swift
func foo<T..., U...>(ts: T..., us: U...) {}

let bar = foo as (Int, Int, Double, Double) -> () // What is T and U supposed to be?
// or
let baz: (Int, Int, Double, Double) -> () = foo // Same problem

```

So the problem remains that we could not reference such a function under this proposal.

---

<div class="post-metadata">

**Author:** ![technicated](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/technicated/32/5420_2.png) [@technicated](https://forums.swift.org/u/technicated)\
**Post date:** [January 10, 2022, 6:49pm UTC](https://forums.swift.org/t/variadic-generics/54511/20 "2022-01-10T18:49:38Z")

</div>

> How about just allow variadic generic parameters to have parameter labels, e.g.:
> 
> ```swift
> struct Broken<A: T..., B: U...>
> typealias Bar = Broken<A: String, B: Int, Void>
> 
> ```
> 
> ... in which case, the type of A is something like, `PackWrapper<T...>` and the type of B is `PackWrapper<U...>` . Thoughts?

Why not directly have the ability to (optionally) specify the parameter name in the specialisation (this may also be generalised to all generic parameters), e.g.

```swift
struct Broken<T..., U...>
typealias Specialised = Broken<T: Int, String, U: Double, Void, String>

```

[Next page](https://forums.swift.org/t/variadic-generics/54511.md?page=2)
