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
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to