This feature is looking great, and this is a very well written proposal to boot! Excited that work on variadic generics continues to move forward. Following are my impressions from a first read through of the pitch, apologies if it is somewhat disorganized.
Types in iterations
I think it would feel natural to express this as:
func allEmpty<T...>(_ arrays: [T]...) -> Bool {
var result = true
for array: EachT in arrays... {
print(EachT.self)
}
return result
}
Of course, there's a secondary problem here about what to call the individual type here, which segues nicely into the next item...
How to name packs
This is somewhat of a tangent, but I think that it's important this document reflect how we expect users to use this feature. I lean towards pack names that explicitly refer to the aggregate such as Rest, Elements, or in the terse case even Ts and Us since this leaves open the natural name of Element or T if we want to use it in, e.g., iteration as above.
I also feel like it's better conceptually. I definitely like the spelling
func prepend<First, Rest...>(...)
to something like
func prepend<First, Next...>(...)
and IMO it reads better in expansions as well, e.g., (Int, Elements..., String). Adopting this convention might also ameliorate some of my concerns with the use of ... in general which, I'll get into next (buckle up).
On ...
I continue to not love the ... spelling as-proposed for the reasons called out in the proposal and ones I discussed in the last pitch. I really don't like that the utterance T... in function parameter position is impossible to decipher without knowing the identity of the type T. I don't consider it a good solution that users can click through to find the definition of T and figure out whether it's a variadic parameter or not. Depending on programming environment this will be at best inconvenient and at worst impossible.
Even in expression context, since value packs can be nested arbitrarily deep within a value pack expansion, users will potentially have to inspect all values referenced within the sub-expression of the ... to reason about what sort of ... they're dealing with.
I understand why ... feels like a natural choice (especially for folks very familiar with C++) but I don't really feel like the proposal makes a very compelling rebuttal of the issues with the ... spelling. While disambiguation rules may allow us to resolve the formal ambiguity, the examples presented still appear horribly ambiguous when reading the code, and I'm not confident that this is just a result of variadic generics being 'fresh' and unfamiliar. Furthermore, I'm not fully convinced by the linguistic arguments for ...:
This is, of course, only one possible linguistic meaning of .... It can also mean trailing off at the end of a sentence...
Or can be used to indicate a pause... in the middle of a sentence. It can also be used (in a quote) to indicate an omission due to irrelevance, and perhaps unintelligibility without further context.
Even accepting the linguistic meaning of ... as omitted information inferred from context, at the end of a list ... frequently indicates that the list is extended by reference to all prior items, not just the one to which ... is affixed. E.g., in "1, 2, 3, 4, 5, 6...", the ellipsis applies to the list as a whole (and not just "6"), which can be seen because the extension implied by the ellipsis in "2, 4, 6..." is entirely different.
I don't think any of these are great reasons to reject the ... absent other concerns, I'm just offering them as reasons why I think the linguistic argument for ... isn't exactly a slam dunk.
A priori, I don't necessarily consider "it's the same way C++ does it!" to be an argument for or against this spelling
. C++ didn't have all the same existing baggage around ... that Swift has, and given that the fundamental model for generics is already quite different between Swift and C++ I'm not too concerned that experienced C++ programmers would also have to learn a slightly different syntax for variadic generics.
To the extent that ... means something different for variadic generics than for normal variadic parameters, I'm not convinced that this is a win. Normal variadic parameters become arrays within the function, while variadic generic parameters become packs/tuples. These are different things with very different feature sets, and I think it's reasonable to spell them differently. Yes, the call sites look the same, but at the point where users would actually be writing ... the behavior is quite different.
This is mostly a very specific argument against the * spelling rather than the idea of an arbitrary different operator. Even the last bullet glosses over the fact that ... is (somewhat) unique within the world of "all operators" in that it is a widely used, standard library operator today, so the exact same ambiguity concerns are far more troublesome to me than they would be for other operators.
Yeah, I think I agree that bare keywords here are probably not a good fit here since the expand operation can be applied to arbitrary expressions, and I like having some broad alignment between the value and type syntax here (so I'm also on board with the reasoning rejecting the magic map operation).
But there's some space between "bare keyword" and "operator" that I'd be curious about, such as #pack(T) and #expand(t). I don't know if we have a great philosophy for what # means in swift broadly other than "special compiler thing" but variadic generics is certainly a special compiler thing, and AFAICT this would address the two points raised here against keyword-style approach.
All this said, I don't have great suggestions for alternatives that I really love either. I don't hate the #pack and #expand option. Operator-wise, doing something like *** could increase visibility while shedding the immediate pointer connection, but ... does have going for it that it's at least easily explainable by analogy with the linguistic ellipsis and I'm not sure there's another good punctuation option that has the same property.
One idea: since we keep using the {T, U} notation to refer to packs, what if we ran with that idea and had packs defined as {T}... and expanded as {t}...? This has the advantage of being a bit more heavyweight than ... alone, as well as being self-delimiting (since it seems like many value pack expansions will need to be parenthesized anyway). There's still a potential ambiguity here with closure expressions, but I don't think it's a formal ambiguity and it's (IMO) more immediately apparent that ... applied to a closure expression doesn't really make any sense.
Same length constraints
I share the discomfort of others with the length(T) syntax and agree that something like T.count is perhaps a bit more ~Swifty~. I wonder if we could also lean into the same-shape idea without introducing the shape terminology by providing a way to declare a sort of 'phantom' constraint that would cause the same-length inference machinery to kick in, e.g.:
func f<T..., U...>(t: T..., u: U...) where (T, U)... // implicitly, 'T' and 'U' must have the same length!
If we went the route of formalizing pack notation, we could also avoid the issue of T.count ambiguity by forcing users to refer to {T}.count or something to make it clear we're referring to an operation on the entire pack and not its constituent members... I guess using the notation I suggested before that would actually be {T}....count but that quadruple dot is awful. 
Multiple variadic type params
I agree this doesn't really need to be addressed in the first proposal, but I do think it would be fine to allow this and permit disambiguation at the call site of (e.g.) an initializer:
struct S<T..., U...> {
init(t: T..., u: U...) {}
}
S(t: 0, "", u: 1.0)
type authors who wanted to provide functionality without passing values would have to jump through some hoops, but maybe that's okay to start out with?
struct S<T..., U...> {
init(t: T.Type..., u: U.Type...)
}
S(t: Int.self, String.self, u: Double.self)
I think this would even allow referring to the metatype, without instantiating at all:
extension S {
static func getMetatype(t: T.Type, u: U.Type) -> S.Type { S.self }
}
let s = S.getMetatype(t: Int.self, String.self, u: Double.self)
Just to take things a bit further, I wonder if the explicit {} syntax for packs would also unblock types with multiple variadic type params. You could instantiate S above as S<{Int, String}..., {Double}...>(). And 'uncallable' functions would become callable as f({arg1, arg2}..., {arg3, arg4}...)