Skip to content

Commit b6ca38b

Browse files
authored
[SE-0393] Minor proposal clarifications. (#1994)
1 parent 6c08c5f commit b6ca38b

File tree

1 file changed

+17
-18
lines changed

1 file changed

+17
-18
lines changed

proposals/0393-parameter-packs.md

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SE-0393: Value and Type Parameter Packs
1+
# Value and Type Parameter Packs
22

33
* Proposal: [SE-0393](0393-parameter-packs.md)
44
* Authors: [Holly Borla](https://github.com/hborla), [John McCall](https://github.com/rjmccall), [Slava Pestov](https://github.com/slavapestov)
@@ -92,9 +92,11 @@ Parameter packs are the core concept that facilitates abstracting over a variabl
9292
func zip<each S: Sequence>(...)
9393
```
9494

95-
A parameter pack itself is not a first-class value or type, but the elements of a parameter pack can be used anywhere that naturally accepts a comma-separated list of values or types using _pack expansions_. A pack expansion unpacks the elements of a pack into a comma-separated list, and elements can be appended to either side of a pack expansion by writing more values in the comma-separated list.
95+
A parameter pack itself is not a first-class value or type, but the elements of a parameter pack can be used anywhere that naturally accepts a list of values or types using _pack expansions_, including top-level expressions.
9696

97-
A pack expansion consists of the `repeat` keyword followed by a type or an expression. The type or expression that `repeat` is applied to is called the _repetition pattern_. The repetition pattern must contain pack references. Similarly, pack references can only appear inside repetition patterns and generic requirements:
97+
A pack expansion consists of the `repeat` keyword followed by a type or an expression. The type or expression that `repeat` is applied to is called the _repetition pattern_. The repetition pattern must contain at least one pack reference, spelled with the `each` keyword. At runtime, the pattern is repeated for each element in the substituted pack, and the resulting types or values are _expanded_ into the list provided by the surrounding context.
98+
99+
Similarly, pack references can only appear inside repetition patterns and generic requirements:
98100

99101
```swift
100102
func zip<each S>(_ sequence: repeat each S) where each S: Sequence
@@ -105,12 +107,11 @@ Given a concrete pack substitution, the pattern is repeated for each element in
105107
Here are the key concepts introduced by this proposal:
106108

107109
- Under the new model, all existing types and values in the language become _scalar types_ and _scalar values_.
108-
- A _type pack_ is a new kind of type which represents a list of scalar types. Type packs do not have syntax in the surface language, but we will write them as `{T1, ..., Tn}` where each `Ti` is a scalar type. Type packs cannot be nested; type substitution is defined to always flatten type packs.
109-
- A _type parameter pack_ is a type parameter which can abstract over a type pack. These are declared in a generic parameter list using the syntax `each T`, and referenced with `each T`.
110-
- A _pack expansion type_ is a new kind of scalar type which flattens a set of type packs in a context where a comma-separated list of types may appear. The syntax for a pack expansion type is `repeat each P`, where `P` is a type containing one or more type parameter packs.
110+
- A _type pack_ is a new kind of type-level entity which represents a list of scalar types. Type packs do not have syntax in the surface language, but we will write them as `{T1, ..., Tn}` where each `Ti` is a scalar type. Type packs cannot be nested; type substitution is defined to always flatten type packs.
111+
- A _type parameter pack_ is a list of zero or more scalar type parameters. These are declared in a generic parameter list using the syntax `each T`, and referenced with `each T`.
111112
- A _value pack_ is a list of scalar values. The type of a value pack is a type pack, where each element of the type pack is the scalar type of the corresponding scalar value. Value packs do not have syntax in the surface language, but we will write them as `{x1, ..., xn}` where each `xi` is a scalar value. Value packs cannot be nested; evaluation is always defined to flatten value packs.
112-
- A _value parameter pack_ is a function parameter or local variable declared with a pack expansion type.
113-
- A _pack expansion expression_ is a new kind of expression whose type is a pack expansion type. Written as `repeat each expr`, where `expr` is an expression referencing one or more value parameter packs.
113+
- A _value parameter pack_ is a list of zero or more scalar function or macro parameters.
114+
- A _pack expansion_ is a new kind of type-level and value-level construct that expands a type or value pack into a list of types or values, respectively. Written as `repeat P`, where `P` is the _repetition pattern_ that captures at least one type parameter pack (spelled with the `each` keyword). At runtime, the pattern is repeated for each element in the substituted pack.
114115

115116
The following example demonstrates these concepts together:
116117

@@ -168,7 +169,7 @@ A pack expansion type, written as `repeat P`, has a *pattern type* `P` and a non
168169
* The type of a parameter in a function type, e.g. `(repeat each T) -> Bool`
169170
* The type of an unlabeled element in a tuple type, e.g. `(repeat each T)`
170171

171-
Because pack expansions can only appear in positions that accept a comma-separated list, pack expansion patterns are naturally delimited by either a comma or the end-of-list delimiter, e.g. `)` for call argument lists or `>` for generic argument lists.
172+
Because pack expansions can only appear in positions that accept a list of types or values, pack expansion patterns are naturally delimited by a comma, the next statement in top-level code, or an end-of-list delimiter, e.g. `)` for call argument lists or `>` for generic argument lists.
172173

173174
The restriction where only unlabeled elements of a tuple type may have a pack expansion type is motivated by ergonomics. If you could write `(t: repeat each T)`, then after a substitution `T := {Int, String}`, the substituted type would be `(t: Int, String)`. This would be strange, because projecting the member `t` would only produce the first element. When an unlabeled element has a pack expansion type, like `(repeat each T)`, then after the above substitution you would get `(Int, String)`. You can still write `0` to project the first element, but this is less surprising to the Swift programmer.
174175

@@ -466,20 +467,20 @@ The type annotation of `tup` contains a pack expansion type `repeat (each T, eac
466467

467468
#### Restrictions on same-shape requirements
468469

469-
While type packs cannot be written directly, a requirement where both sides are concrete types is desugared using the type matching algorithm, therefore it will be possible to write down a requirement that constrains a type parameter pack to a concrete type pack, unless some kind of restriction is imposed:
470+
Type packs cannot be written directly, but requirements involving pack expansions where both sides are concrete types are desugared using the type matching algorithm. This means it is possible to write down a requirement that constrains a type parameter pack to a concrete type pack, unless some kind of restriction is imposed:
470471

471472
```swift
472-
func append<each S: Sequence>(_: repeat each S, _: repeat each T) where (each S).Element == (Int, String) {}
473+
func constrain<each S: Sequence>(_: repeat each S) where (repeat (each S).Element) == (Int, String) {}
473474
```
474475

475-
Furthermore, since the same-type requirement implies a same-shape requirement, we've implicitly constrained `T` to having a length of 2 elements, without knowing what those elements are.
476+
Furthermore, since the same-type requirement implies a same-shape requirement, we've implicitly constrained `S` to having a length of 2 elements, without knowing what those elements are.
476477

477478
This introduces theoretical complications. In the general case, same-type requirements on type parameter packs allows encoding arbitrary systems of integer linear equations:
478479

479480
```swift
480481
// shape(Q) = 2 * shape(R) + 1
481482
// shape(Q) = shape(S) + 2
482-
func solve<each Q, each R, each S>(q: repeat each Q, r: repeat each R, s: repeat eachS)
483+
func solve<each Q, each R, each S>(q: repeat each Q, r: repeat each R, s: repeat each S)
483484
where (repeat each Q) == (Int, repeat each R, repeat each R),
484485
(repeat each Q) == (repeat each S, String, Bool) { }
485486
```
@@ -500,7 +501,7 @@ This aspect of the language can evolve in a forward-compatible manner. Over time
500501

501502
### Value parameter packs
502503

503-
A _value parameter pack_ represents zero or more function arguments, and it is declared with a function parameter that has a pack expansion type. In the following declaration, the function parameter `value` is a value parameter pack that receives a _value pack_ consisting of zero or more argument values from the call site:
504+
A _value parameter pack_ represents zero or more function or macro parameters, and it is declared with a function parameter that has a pack expansion type. In the following declaration, the function parameter `value` is a value parameter pack that receives a _value pack_ consisting of zero or more argument values from the call site:
504505

505506
```swift
506507
func tuplify<each T>(_ value: repeat each T) -> (repeat each T)
@@ -510,7 +511,7 @@ _ = tuplify(1) // T := {Int}, value := {1}
510511
_ = tuplify(1, "hello", [Foo()]) // T := {Int, String, [Foo]}, value := {1, "hello", [Foo()]}
511512
```
512513

513-
**Syntactic validity:** A value parameter pack can only be referenced from a pack expansion expression. A pack expansion expression is written as `repeat expr`, where `expr` is an expression containing one or more value parameter packs or type parameter packs spelled with the `each` keyword. Pack expansion expressions can appear in any position that naturally accepts a comma-separated list of expressions. This includes the following:
514+
**Syntactic validity:** A value parameter pack can only be referenced from a pack expansion expression. A pack expansion expression is written as `repeat expr`, where `expr` is an expression containing one or more value parameter packs or type parameter packs spelled with the `each` keyword. Pack expansion expressions can appear in any position that naturally accepts a list of expressions, including comma-separated lists and top-level expressions. This includes the following:
514515

515516
* Call arguments, e.g. `generic(repeat each value)`
516517
* Subscript arguments, e.g. `subscriptable[repeat each index]`
@@ -519,8 +520,6 @@ _ = tuplify(1, "hello", [Foo()]) // T := {Int, String, [Foo]}, value := {1, "hel
519520

520521
Pack expansion expressions can also appear in an expression statement at the top level of a brace statement. In this case, the semantics are the same as scalar expression statements; the expression is evaluated for its side effect and the results discarded.
521522

522-
Note that pack expansion expressions can also reference _type_ pack parameters, as metatypes.
523-
524523
**Capture:** A pack expansion expression _captures_ a value (or type) pack parameter the value (or type) pack parameter appears as a sub-expression without any intervening pack expansion expression.
525524

526525
Furthermore, a pack expansion expression also captures all type parameter packs captured by the types of its captured value parameter packs.
@@ -834,4 +833,4 @@ extension<each T: Equatable> (repeat each T): Equatable {
834833

835834
## Acknowledgments
836835

837-
Thank you to Robert Widmann for exploring the design space of modeling packs as tuples, and to everyone who participated in earlier design discussions about variadic generics in Swift.
836+
Thank you to Robert Widmann for exploring the design space of modeling packs as tuples, and to everyone who participated in earlier design discussions about variadic generics in Swift. Thank you to the many engineers who contributed to the implementation, including Sophia Poirier, Pavel Yaskevich, Nate Chandler, Hamish Knight, and Adrian Prantl.

0 commit comments

Comments
 (0)