[Idea] Passing an Array to Variadic Functions


(Justin Jia) #1

Hi!

Currently, we can’t call a variadic function with an array of arguments.

Reference:
1. http://stackoverflow.com/questions/24024376/passing-an-array-to-a-function-with-variable-number-of-args-in-swift
2. https://www.drivenbycode.com/the-missing-apply-function-in-swift/

Consider the following use case:

func average(numbers: Double…) -> Double {
    return sum(numbers) / numbers.count // Error: Cannot convert value of type ‘[Double]’ to expected argument type ‘Double'
}

func sum(numbers: Double...) -> Double { … }

Right now, there are two ways to fix it:

1. Add another function that accept `[Double]` as input.

func average(numbers: Double…) -> Double {
    return sum(numbers) / numbers.count
}

func sum(numbers: Double...) -> Double {
    return sum(numbers)
}

func sum(numbers: [Double]) -> Double { … }

2. Implement an `apply()` function using `unsafeBitCast`.

func average(numbers: Double…) -> Double {
    return sum(apply(numbers)) / numbers.count
}

func sum(numbers: [Double]) -> Double { … }

func apply<T, U>(fn: (T...) -> U, args: [T]) -> U {
    typealias FunctionType = [T] -> U
    return unsafeBitCast(fn, FunctionType.self)(args)
}

However, both solutions are not very elegant. The first solution requires the library author to implement both functions, and the second solution breaks the guarantees of Swift’s type system.

Swift should allow passing an array to variadic functions, or we should implement a type-safe `apply()` function in the standard library.

Justin


(Dave Abrahams) #2

Yes, having a way to forward an array to a variadic function is
something we've always wanted but have never gotten around to
implementing.

···

on Fri Apr 15 2016, Justin Jia <swift-evolution@swift.org> wrote:

Hi!

Currently, we can’t call a variadic function with an array of arguments.

Reference:
1. http://stackoverflow.com/questions/24024376/passing-an-array-to-a-function-with-variable-number-of-args-in-swift
2. https://www.drivenbycode.com/the-missing-apply-function-in-swift/

Consider the following use case:

func average(numbers: Double…) -> Double {
    return sum(numbers) / numbers.count // Error: Cannot convert value of type ‘[Double]’ to expected argument type ‘Double'
}

func sum(numbers: Double...) -> Double { … }

Right now, there are two ways to fix it:

1. Add another function that accept `[Double]` as input.

func average(numbers: Double…) -> Double {
    return sum(numbers) / numbers.count
}

func sum(numbers: Double...) -> Double {
    return sum(numbers)
}

func sum(numbers: [Double]) -> Double { … }

2. Implement an `apply()` function using `unsafeBitCast`.

func average(numbers: Double…) -> Double {
    return sum(apply(numbers)) / numbers.count
}

func sum(numbers: [Double]) -> Double { … }

func apply<T, U>(fn: (T...) -> U, args: [T]) -> U {
    typealias FunctionType = [T] -> U
    return unsafeBitCast(fn, FunctionType.self)(args)
}

However, both solutions are not very elegant. The first solution
requires the library author to implement both functions, and the
second solution breaks the guarantees of Swift’s type system.

Swift should allow passing an array to variadic functions, or we
should implement a type-safe `apply()` function in the standard
library.

--
Dave