[Proposal] Variadics as Attribute

I agree that we should have a way to call a variadic function with an Array at hand, without needing to take its elements apart (`foo(x[0], x[1], x[2])`) — which indeed is only practical when we statically know its length.

But I fear there's a shortcoming in this proposal that hasn't been addressed: How would the compiler clear the ambiguity in single-argument calls between existentials such as `Any` or `CustomStringConvertible` and sequences thereof (e.g. `[Any]` or `[CustomStringConvertible]`, which both can be treated as `Any` and `CustomStringConvertible` as well?

If you take this function for example,

    func printThem(@variadic _ values: [Any])

then what would `values` be in the following calls, and why?

    printThem() // clearly
    printThem(1) // clearly [1]
    printThem(1, 2) // clearly [1, 2]
    printThem([1], [2]) // clearly [[1], [2]]
    printThem() // or [], which one?
    printThem([1]) // [1] or [[1]]?
    printThem([1, 2]) // [1, 2] or [[1, 2]]?

I think it would be less painful a change (i.e. can be delayed past Swift 3) if we just augment what we have (the `...` argument declaration syntax) with a way to expand an Array in place of a variadic argument:

    func printThem(_ values: Any...)

    printThem(1) // values == [1]
    printThem([1]) // values == [[1]]
    // Possible expansion postfix syntax:
    printThem([1]...) // values == [1]
    // Expanding a non-array sequence:
    let things: Set<Int> = [1, 2, 3]
    printThem(Array(things)...)

I think variadic functions are intended for human convenience and rarely used in performance-critical code, and it's probably more convenient that they're always passed as an Array, and not as a generic sequence.

— Pyry

Haravikk wrote:

···

For example, consider the following variadic function:

func someMethod(_ values:Int...) { … }
Under this proposal the above can be rewritten as one of the following:

func someMethod(@variadic _ values:[Int]) { … } // Basic Array solution
func someMethod(@variadic _ values:Foo) { … } // Foo is a custom ArrayLiteralConvertible type
func someMethod<I:IteratorProtocol where I.Element == Int>(@variadic _ values:I) { … } // Flexible, single-pass, generic solution
func someMethod<S:Sequence where S.Iterator.Element == Int>(@variadic _ values:S) { … } // Flexible, (probably) multi-pass, generic solution
func someMethod<C:Collection where C.Iterator.Element == Int>(@variadic _ values:C) { … } // Flexible, definitely multi-pass, indexed, generic solution
In this case the Iterator variation is preferred for greatest flexibility, but it will depend upon the actual requirements of the method. Any of these can be called as follows:

someMethod([1, 2, 3, 4, 5, 6]) // normal array-literal call for any of the above
someMethod(1, 2, 3, 4, 5, 6) // variadic call, synonymous with array-literal call
someMethod(foo) // foo is an existing Array, Foo, Iterator, Sequence or Collection variable as appropriate