@technicated, I just gave the variadic generics document a read and it really looks great! Thank you for putting all of this together. I'm very excited for what the future has in store for Swift generics.
A couple questions... I was wondering if one will be able to write extensions on variadics (sort of like the project(_:)
method AFAIU) like it is a regular protocol conforming to Collection
? Also, is there any value in being able to have more fine-grained control over the number of arguments that a given variadic can accept (i.e. restricting a variadic parameter to only take a max number of arguments or a minimum number of arguments)? Something like that would allow you to leave out the first two parameters of you Variadic Generic version of the zip
function by restricting the variadic parameter to 2 or more arguments.
I just wanted to bring your attention to a few minor fixes I found while reviewing the current version of your Variadic Generics proposal:
Spelling Errors (12):
Correct "thells" to "tells" and "wether" to "whether" in comments in
collectionApi(t:u:)
method in Variadic Value API section.// thells wether `T` was specialized with 0 parameters // (and therefore `t` contains no elements at all) print(t.isEmpty)
Correct "regualr" to "regular" in last line of Motivation section.
Let's take a look at some examples that are hard or impossible to "scale up" today with regualr Swift.
Correct "clutterness" to "clutter" in Example 3: variadic sorting.
SwiftUI and its
ViewBuilder
function builder type suffer from the same problem.ViewBuilder
has a fixed amount ofbuildBlock
methods that takeC0
,C1
,C2
and so on subviews, leading again to code duplication and clutterness.Correct "toghether" to "together" in Proposed Solution section.
> This means, for example, that if there exists a function parametrised by a Variadic Generic conforming to the `Collection` protocol you can pass to this function an `Array` , a `Dictionary` and a `String` - all toghether - because all these types conform to `Collection` .
Correct "postifx" to "postfix" in Proposed Solution section.
A variadic value can also be passed as the variadic argument of a variadic function (yay!). I mildly suggest the operation is again performed by using the
...
syntax to explicitly indicate what's happening (but here, much more than in the tuple context, the...
can be mistaken for a postifx operator... suggestions are welcome):Replace first "of" with "as" in the final portion of the Proposed Solution section.
What can be noted in this example is that the code is practically the same of the current, non-variadic
zip
implementation. The only real difference is thatzip
can now be used to zip any number of arbirtary and different sequences together!Correct "arbirtary" to "arbitrary" in the final portion of the Proposed Solution section.
What can be noted in this example is that the code is practically the same of the current, non-variadic
zip
implementation. The only real difference is thatzip
can now be used to zip any number of arbirtary and different sequences together!Correct "previos" to "previous" in link in Introduction section.
This document is kind of a follow up to a previos one by Austin Zheng - "kind of" because I've read the document, but not too in depth - and this was intentional.
Correct "parametrised" to "parameterized" in Proposed Solution section.
This means, for example, that if there exists a function parametrised by a Variadic Generic conforming to the
Collection
protocol you can pass to this function anArray
, aDictionary
and aString
- all toghether - because all these types conform toCollection
.Correct "Variadig" to "Variadic" in comments under Declaring and using Variadic Generic functions section.
// The following code will cause a compile-time error like "Variadig generic // argument does not need `...`. Remove it." - a fixit can also be suggested func wrongVariadicGenericFunction<T: variadic Any>(ts: T...) { }
Correct "declarered" to "declared" in comments under Declaring and using Variadic Generic functions section.
// ============================================================================= // The `(T...)` syntax is also taken into account, allowing a tuple to be passed // as a parameter to a Variadic Generic function. Two functions declarered with // both `T` and `(T...)` syntax are different will participate in overload reso- // lution. // ============================================================================= func overloaded<T: variadic P1>(ts: T) { } func overloaded<T: variadic P1>(ts: (T...)) { }
Correct "trasforming" to "transforming" in first comment under Variadic Value API section.
// ============================================================================= // Variadic values conform to the `RandomAccessCollection` protocol and enhance // it in various ways. All the standard `Collection` API can be used, and all // the standard functionality (for ... in loops, etc) is available. Moreover, // all the "trasforming" members are overloaded to return another variadic value // instead of an `Array`, and due to how overload resolution works these func- // tions will be the preferred one when no type context is given. // =============================================================================
-
Grammatical Errors (20):
Insert comma after "compiler" in comments under the Declaring and using a Variadic Generic section.
// When there is ambiguity in case of multiple Variadic Generics, the type sys- // tem prefers to assign the maximum number of types to the first generic param- // eter. The parameter name can be used to manually resolve the ambiguity, and // for the happines of the compiler this concept may be generalized to all // generic parameters even if this is not strictly needed. This new syntax does // not allow the reordering of the generic parameters. The compiler is updated // to show new and more detailed informations about generic parameters.
Hyphenate "in depth" in Introduction section.
This document is kind of a follow up to a previos one by Austin Zheng - "kind of" because I've read the document, but not too in depth - and this was intentional.
Insert comma after "Obviously" in Introduction section.
Obviously the information contained in the mentioned document and collected on the Swift Forums are going to influence what's presented there.
Insert comma after "unfortunately" in first part of Motivation section.
Today it is impossible or very difficult to express patterns related to an unbounded amount of generic types or values. Maybe the closest thing we have is variadic functions, but unfortunately such functions require all of their arguments to be of the same concrete type
Insert comma after "way" in Example 3: variadic sorting.
In this way animals are sorted by name, and if their name is the same they are sorted by their age, and so on. But if we try to declare the function in the naïve way we get an error:
Insert commas before and after "in this case" in Example 3: variadic sorting.
This example might again seem similar to the
zip
one. The difference in this case is that Variadic Generics are not used "directly" in the function signature, but are used instead to construct another type that depends on them i.e.KeyPath<Element, T>
.Insert comma after "in other words" in Example 5: curry.
A curried function is one that takes multiple arguments but one at a time - in other words a curried function takes the first argument and returns a new function taking the second argument and so on until all arguments are used and the result is returned.
Insert comma after "context" in Proposed Solution section.
Inside of a generic context a Variadic Generic can be directly used as a type. A value whose type is a Variadic Generic is called a variadic value, and is a collection of zero or more values (more on this later) implementing the
Collection
protocol:Insert comma after "section" in Detailed Design section.
In this section we are going to see how Variadic Generics can be declared and used in various contexts.
Insert comma after "case" in comments above
vg3
declaration in Declaring and using a Variadic Generic section.// The name of the generic parameter can be used to specify how the // specialization should be done; note that in this case all the labels are // specified for clarity but not all of them are really required let vg3: ComplexVariadic<A: Double, B: Int, T: Int, String, U: String, String> // vg3: ComplexVariadic<A: Double, B: Int, T: <Int, String>, U: <String, String>>
</details>
Insert comma after "because" and ", they" after "generic context" under Variadic Values section.
Insert "elements" before "passed" in comments in
collectionApi(t:u:)
method under Variadic Value API section.// Get one of the `P1` passed to `t` print(t.randomElement()) // The `Index` type is an `Int` and subscripts are 0-based // The same as `t.first` or a nice crash print(t[0])
Insert "`ts`" after "first function" in comments under Declaring and using Variadic Generic functions section.
func wrongVariadicGenericFunction<T: variadic Any>(ts: T...) { } // ============================================================================= // The two functions declared above are somewhat equivalent from the outside be- // cause `T` was not constrained in any way. The only difference is that in the // second function `ts` is of type `[Any]` while in the first function is of // type `variadic Any`.
Insert commas after "second function", "type `[Any]`", "first function", and "snippet" in comments under Declaring and using Variadic Generic functions section
func wrongVariadicGenericFunction<T: variadic Any>(ts: T...) { } // ============================================================================= // The two functions declared above are somewhat equivalent from the outside be- // cause `T` was not constrained in any way. The only difference is that in the // second function `ts` is of type `[Any]` while in the first function is of // type `variadic Any`. // // In the following snippet we instead actually have a difference: the second // function can inded accept parameters of any type, but only if all of them are // of the **same** type! The first function does not have this limitation. // =============================================================================
Insert "and" after "different" in comments under Declaring and using Variadic Generic functions section.
// ============================================================================= // The `(T...)` syntax is also taken into account, allowing a tuple to be passed // as a parameter to a Variadic Generic function. Two functions declarered with // both `T` and `(T...)` syntax are different will participate in overload reso- // lution. // ============================================================================= func overloaded<T: variadic P1>(ts: T) { } func overloaded<T: variadic P1>(ts: (T...)) { }
Replace "The usage of the" with "Note, the" in comment under Declaring and using Variadic Generic functions section.
// ============================================================================= // A Variadic Generic can directly be used as the result type of a function, and // it will be automatically considered a `Collection` in concrete code. The us- // age of the `(T...)` syntax is used to make the result type a tuple. // =============================================================================
Hyphenate "fixit" in comment under Declaring and using Variadic Generic functions section.
// The following code will cause a compile-time error like "Variadig generic // argument does not need `...`. Remove it." - a fixit can also be suggested func wrongVariadicGenericFunction<T: variadic Any>(ts: T...) { }
Replace "another" with "a" and add comma after "overload resolution works" in first comment under Variadic Value API section.
// ============================================================================= // Variadic values conform to the `RandomAccessCollection` protocol and enhance // it in various ways. All the standard `Collection` API can be used, and all // the standard functionality (for ... in loops, etc) is available. Moreover, // all the "trasforming" members are overloaded to return another variadic value // instead of an `Array`, and due to how overload resolution works these func- // tions will be the preferred one when no type context is given. // =============================================================================
Replace "the other" with "another", remove comma after "fair", insert comma after "However", replace ", and for this reason variadic" with ". For this reason, variadic" in comment under Variadic Value API section.
// ============================================================================= // The "transforming" functions need a little bit more attention. We have two // overloads of `map`, one that returns an `Array` and the other that returns a // variadic value - but those overloads do not allow modifications to the under- // lying collection element. And this is fair, because programmers expect a // `map` to be pure. // However sometimes it might be useful to mutate the original variadic value // while creating a new one, and for this reason variadic values offer an origi- // nal `project` method. // // *NOTE:* the name is subject to debate, `project` is the best (and sound) that // I could find. // =============================================================================
Remove "Obviously", replace semicolon with comma, and remove comma after "topic" in Introduction section.
I've never worked too much with variadic generics in my programming life and I wanted to start "fresh" and as unbiased as possible on the topic, to see if I could come up with new or interesting ideas; but it's also possible that this document ends up sharing a lot of similarities with Austin's! Obviously the information contained in the mentioned document and collected on the Swift Forums are going to influence what's presented there.
Capitalize "values" in "Variadic values" header in Variadic Values section.
// ============================================================================= // Variadic values are somewhat "special", because both inside and outside of a // generic context act like a `Collection` - or better *are* a `Collection`. The // `Element` of this collection is the constraint of the Variadic Generic. In- // side a generic context, the `...` syntax allows users to convert this collec- // tion to a tuple whose shape and types will be the concrete types passed to // the Variadic Generic parameter. //
-
Other Errors (2):
Add "swift" after "```" to enable syntax highlighting under code block under Variadic Values.
// ============================================================================= // Variadic values are somewhat "special", because both inside and outside of a // generic context act like a `Collection` - or better *are* a `Collection`. The // `Element` of this collection is the constraint of the Variadic Generic. In- // side a generic context, the `...` syntax allows users to convert this collec- // tion to a tuple whose shape and types will be the concrete types passed to // the Variadic Generic parameter. //
In the example function,
overloadedApis
, under the Variadic Value API section, you make reference to a value,t
, that I think you just forgot to add as a parameter to the function.func overloadedApis() { // No type specified - this is a variadic value of `Any`s let aVariadicValue = t.map { $0.someMember } // A type (`[Any]`) was specified - this is an array of `Any`s let anArray: [Any] = t.map { $0.someMember } // `SubSequence` is another variadic value, whose type is still `variadic P1` let subVariadicValue = t.dropFirst() // This works, subVariadicValue is unpacked and passed to the parameter // `values` of the called function _ = explicitlyMakeTuple(subVariadicValue) }