Variadic Generics

generics
(Andrea Tomarelli) #62

I also only now realized that I did not invite @Austin to join this thread - I apologise! If you are still interested in this area I'd love to hear your comments too!

(Andrea Tomarelli) #63

The YYYY document now contains details about the for ... in syntax and some craziness with compile-time helpers and recursive Variadic Generics (Curry example)... I guess it's a start!

1 Like
(Daryle Walker) #64

Should there be a "#countOf" function on a variadic pack to extract the length of the pack? It should be @constexpr whenever possible. Should we require @constexpr support first before adding the count operation? I'm not sure when it would be useful for now, though.

(Luiz Fernando) #65

I feel like we need support of some sort to disambiguate a foo<T...>(args: AGenericType<T>) between being args: AGenericType<A, B, C> or args: AGenericType<A>, AGenericType<B>, AGenericType<C>.

For example, from your document:

extension Array {
  func sort<T: Comparable>(_ sortProperties: KeyPath<Element, T>...) {
    [...]
  }
}

We must have a way to express that sortProperties is actually 'a variadic list of KeyPath types, one for each type in T', like telling the compiler to map each T in T... using a partial type function * -> KeyPath<Element, *>, resulting in the final variadic type of sortProperties. Otherwise it could look ambiguous to the compiler, and the user:

extension Array {
  func sort<variadic T: Comparable>(_ sortProperties: KeyPath<Element, T>...) {
    [...]
  }
}

Is sortProperties an array of KeyPath<Element, T1, T2, T3, ...>, or one variadic type KeyPath<Element, T1>, KeyPath<Element, T2>, ...?

I feel like it is important to support expressing both of those when the user sees fit:

// 1.: A list of generic types specialized with each T:
extension Sequence {
  mutating func assigning<variadic T>(keyPaths: WritableKeyPath<Element, T>...,  values: T...) -> [Element] { // detect variadic `T` and interpret ellipsis as many specializations of `WritableKeyPath`s? I dunno about this one...
    [...]
  }
}

people.assigning(keyPaths: \.name, .\age, 
                 values: "John Smith", 26)

// 2.: One type specialized once, with the whole variadic list:
func toArray<variadic T>(_ zip: ZipCollection<T...>) -> [T...] { // ellipsis in type parameter list could mean "splat"
    [...]
}

toArray(someZipCollection) // (ZipCollection<Int, String, Double>) -> [(Int, String, Double)]

(This is just a weak shot at a syntax (and use cases) to illustrate the point, btw).

(Andrea Tomarelli) #66

Thank you both for your feedback!


@CTMacUser yeah, I also think that an utility to get the number of elements of a variadic item might be useful, event if we do not have @constexpr. I'm also not sure if, in some dynamic cases, the element count could be evaluated at compile time! So maybe no need for @constexpr at all.


@Luiz you are right, and I thought I outlined it in the document! If this is not the case, it's possibile that I wrote about this potential issue in the second document, an updated copy / version of the first one that I'm working on to update stuff!

That aside, my idea is that we should simply not allow the mixing of VGs and variadic functions, in order to avoid confusion and unnecessary complexity. I could not find a scenario in which it was useful to combine the two things, but that my just be me!

This means that, in my opinion, a compiler error should be raised in the following case:

func aVariadicFunction<variadic Args: SomeEventualProtocol>(_ args: Args...) {
  [...]
}
// error: Variadic generic argument do not require the use of `...`. Remove it.
// func aVariadicFunction<variadic Args: SomeEventualProtocol>(_ args: Args...) {
//                                                                     ^~~~