[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 somehow implement a type-safe `apply()` function in the standard library.

Justin


array splatting for variadic parameters
[Discussion] Forwarding of variadic arguments
(Keith Smiley) #2

We've been dealing with this as well. We've chosen to go with your option 1 for
most of our cases, sometimes dropping varargs all together and just using the
array signature.

It would be great if you could have a safe apply function for this.

···

--
Keith Smiley

On 04/17, Justin Jia via swift-evolution 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 somehow implement a type-safe `apply()` function in the standard library.

Justin

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Daniel Duan) #3

Justin Jia via swift-evolution <swift-evolution@...> writes:

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

IMO, this would be a useful addition. Here are my thoughts on the thread so
far as an imaginary Q&A.

"Why not remove vararg instead?"

As others have mentioned, this feature enable us to write cleaner code. I
first learned to appreciate it in C, where some books would introduce it as the
way to implement printf(). I really prefer not to create an array on unrelated
items just to print() them in Swift.

"Will it be useful in real life?"

If we keep vararg, then enhancing it with a splat feature will make it far
more useful than it is today. One of my colleague (hi Scott!) encountered its
limits just last week: once the varadic argumntes becomes an array, there's no
way to get them "back" as arguments. This becomes an issue if our function
needs to forward part of its received arguments recursively to itself. Either
of the following would be great:

func foo(a: Int...) {
    if !a.isEmpty() {
        apply(foo, a.dropFirst()) // imaginary apply function.
        foo(a: #splat(a.dropFirst())) // imaginary splat, syntax TBD.
    }
}

Therefore, +1.


(Radek Pietruszewski) #4

I think it’s pretty clear that if we have a syntax for passing an array to a variadic argument it should be:

  func(array…)

This would be symmetric with variadic type signature, and similar to how other languages do it (i.e. in Ruby, declaration is `*args` and array splat is also `*args`). The operator is necessary for disambiguation (in the `Any…` case and the like).

My guess is that it just hasn’t been implemented, but if we get a formal proposal, then maybe we can put it to review and then it shouldn’t be hard to get it implemented in Swift 3.0 timeframe.

The `…` operator would also be great in a different, but similar case — tuple splat, i.e. if you have a function `(T, U) -> Whatever`, and a tuple `(T, U)`, you could pass it to the function using `function(tuple…)`. (Implicit tuple splat was removed…)

Best,
— Radek

···

On 17 Apr 2016, at 19:12, Justin Jia via swift-evolution <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 somehow implement a type-safe `apply()` function in the standard library.

Justin
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Howard Lovatt) #5

Why not remove varargs altogether from Swift, it is easy enough to put []
round a list?

···

On Monday, 18 April 2016, Keith Smiley via swift-evolution < swift-evolution@swift.org> wrote:

We've been dealing with this as well. We've chosen to go with your option
1 for
most of our cases, sometimes dropping varargs all together and just using
the
array signature.

It would be great if you could have a safe apply function for this.

--
Keith Smiley

On 04/17, Justin Jia via swift-evolution 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
<
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/ <
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
somehow implement a type-safe `apply()` function in the standard library.
>
> Justin

> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <javascript:;>
> https://lists.swift.org/mailman/listinfo/swift-evolution

--
-- Howard.


(Tony Allevato) #6

I would also be supportive of removing varargs for now, in favor of a
rethought design when generics are completed.

In their current form, varargs are fairly limited—because they're mapped
onto an array, the argument types must be homogeneous, so either your
function can only usefully take a single type of argument, or you
potentially lose information because they have to be upcast to a common
supertype or Any in order to build the array.

I'm not convinced that varargs produce code that is much cleaner than the
array version. Is this:

  String(format: "%@ is %d years old", name, age)

that much cleaner than:

  String(format: "%@ is %d years old", arguments: [name, age])

Perhaps slightly, but I'm not sure it's worth the special case. The
function implementor can even get rid of the second argument name if they
wanted to make it cleaner. And if the function you're calling takes varargs
as its sole argument, the only difference is two brackets.

Varargs in their current form seem like a historical vestige from languages
like C and Java where there was no syntax to cleanly create an anonymous
array literal. Swift doesn't have that limitation.

That being said, where varargs *do* become considerably more useful is when
generics are completed and you can have variadic type argument lists. But
in that case, the implementation is completely different because (if Swift
followed C++'s design) you'd be working with a parameter pack instead of an
array, and you would have operations that let you manipulate that pack
while preserving the compile-time type information of those arguments.

IMO, handling it that way seems like a better approach than trying to graft
something to bridge varargs and arrays.

···

On Mon, Apr 18, 2016 at 11:14 AM Daniel Duan via swift-evolution < swift-evolution@swift.org> wrote:

Justin Jia via swift-evolution <swift-evolution@...> writes:

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

IMO, this would be a useful addition. Here are my thoughts on the thread so
far as an imaginary Q&A.

"Why not remove vararg instead?"

As others have mentioned, this feature enable us to write cleaner code. I
first learned to appreciate it in C, where some books would introduce it
as the
way to implement printf(). I really prefer not to create an array on
unrelated
items just to print() them in Swift.

"Will it be useful in real life?"

If we keep vararg, then enhancing it with a splat feature will make it far
more useful than it is today. One of my colleague (hi Scott!) encountered
its
limits just last week: once the varadic argumntes becomes an array,
there's no
way to get them "back" as arguments. This becomes an issue if our function
needs to forward part of its received arguments recursively to itself.
Either
of the following would be great:

func foo(a: Int...) {
    if !a.isEmpty() {
        apply(foo, a.dropFirst()) // imaginary apply function.
        foo(a: #splat(a.dropFirst())) // imaginary splat, syntax TBD.
    }
}

Therefore, +1.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Vladimir) #7

About print() and similar: this should be (in case we remove variadic params) overloaded functions with different number of params.

func print()
func print(v1: Any)
func pring(v1, v2: Any) etc

As for #splat. Should we have such problems in working with params or should we introduce one more layer of "collection of params" and methods for it, instead of explicit use of array of params?

And do you like implicit tuple splat in method/functions? :wink:

In case the most of us supports variadic params : Should we introduce some special marker to mark them in code? I feel that we just need such a way to tell that "we are calling this method with variadic params", this will be in Swift way.
For example select(: id, name, count) or in some other way.
(or select(* id, name, count) or select(# id, name, count).. hm.. just like in "Alternatives considered" in SE-0029 with comment:
foo(*x) // NOT a serious syntax proposal)

P.S. As currently we did remove C-like for(;:wink: loops and ++ - don't think that this "variadic params" feature that is coming from the same C should exists in language. Otherwise I can't feel that Swift team is consistent.

···

On 18.04.2016 21:14, Daniel Duan via swift-evolution wrote:

Justin Jia via swift-evolution <swift-evolution@...> writes:

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

IMO, this would be a useful addition. Here are my thoughts on the thread so
far as an imaginary Q&A.

"Why not remove vararg instead?"

As others have mentioned, this feature enable us to write cleaner code. I
first learned to appreciate it in C, where some books would introduce it as the
way to implement printf(). I really prefer not to create an array on unrelated
items just to print() them in Swift.

"Will it be useful in real life?"

If we keep vararg, then enhancing it with a splat feature will make it far
more useful than it is today. One of my colleague (hi Scott!) encountered its
limits just last week: once the varadic argumntes becomes an array, there's no
way to get them "back" as arguments. This becomes an issue if our function
needs to forward part of its received arguments recursively to itself. Either
of the following would be great:

func foo(a: Int...) {
    if !a.isEmpty() {
        apply(foo, a.dropFirst()) // imaginary apply function.
        foo(a: #splat(a.dropFirst())) // imaginary splat, syntax TBD.
    }
}

Therefore, +1.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dennis Weissmann) #8

Why not remove varargs altogether from Swift, it is easy enough to put [] round a list?

+1, that was my thought too. I can’t think of a use case where you can’t use an array instead of varargs (this assumes all vararg parameters are converted to array parameters).

- Dennis

···

On Apr 18, 2016, at 12:48 AM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

Why not remove varargs altogether from Swift, it is easy enough to put [] round a list?

On Monday, 18 April 2016, Keith Smiley via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
We've been dealing with this as well. We've chosen to go with your option 1 for
most of our cases, sometimes dropping varargs all together and just using the
array signature.

It would be great if you could have a safe apply function for this.

--
Keith Smiley

On 04/17, Justin Jia via swift-evolution 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 <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/ <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 somehow implement a type-safe `apply()` function in the standard library.
>
> Justin

> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <>
> https://lists.swift.org/mailman/listinfo/swift-evolution

--
-- Howard.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Brent Royal-Gordon) #9

I would like to see format strings go away and be replace with safer inline annotations.

The main problem is doing localized strings with printf-style formats well, but I actually have a pretty sweet solution for that: https://gist.github.com/brentdax/79fa038c0af0cafb52dd

-- E, somewhat agnostic on variadics

Variadics are eventually important as a generic function feature; you really want to be able to write a version of zip() which can take any number of sequences, for instance, and the only reasonable way to do that is to pass a variable number of parameters and return a sequence with a matchingly variable number of type parameters.

Today, they are important in that they bootstrap ArrayLiteralConvertible and DictionaryLiteralConvertible by (at least theoretically) acting as a pass-N-items mechanism that doesn't depend on one of the standard library types defined in terms of it. (If we convert them to show up as tuples once we have tuple subscripting syntax, that will even become true.) Less esoterically, they're used in several places where an Array would be inconvenient or break traditions:

* The `print` function's list of items to print is variadic. An array equivalent would look like `print([one, two, three])`.
* The `min` and `max` functions are more convenient than explicitly constructing an array and calling their `min()` and `max()` methods.
* And, yes, `String.init(format:_:)`, which we will probably never be quite rid of for compatibility reasons.

···

--
Brent Royal-Gordon
Architechies


(Erica Sadun) #10

I would like to see format strings go away and be replace with safer inline annotations.

-- E, somewhat agnostic on variadics

···

On Apr 18, 2016, at 1:01 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

I would also be supportive of removing varargs for now, in favor of a rethought design when generics are completed.

In their current form, varargs are fairly limited—because they're mapped onto an array, the argument types must be homogeneous, so either your function can only usefully take a single type of argument, or you potentially lose information because they have to be upcast to a common supertype or Any in order to build the array.

I'm not convinced that varargs produce code that is much cleaner than the array version. Is this:

  String(format: "%@ is %d years old", name, age)

that much cleaner than:

  String(format: "%@ is %d years old", arguments: [name, age])


(Erica Sadun) #11

This is why god gave us bike sheds.

Maybe "My earned interest rate this year is \({02.2}theRate)%!"

-- E

···

On Apr 18, 2016, at 1:23 PM, Ricardo Parada <rparada@mac.com> wrote:

What would that look like?

On Apr 18, 2016, at 3:06 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 18, 2016, at 1:01 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

I would also be supportive of removing varargs for now, in favor of a rethought design when generics are completed.

In their current form, varargs are fairly limited—because they're mapped onto an array, the argument types must be homogeneous, so either your function can only usefully take a single type of argument, or you potentially lose information because they have to be upcast to a common supertype or Any in order to build the array.

I'm not convinced that varargs produce code that is much cleaner than the array version. Is this:

String(format: "%@ is %d years old", name, age)

that much cleaner than:

String(format: "%@ is %d years old", arguments: [name, age])

I would like to see format strings go away and be replace with safer inline annotations.

-- E, somewhat agnostic on variadics

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Ricardo Parada) #12

What would that look like?

···

On Apr 18, 2016, at 3:06 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 18, 2016, at 1:01 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

I would also be supportive of removing varargs for now, in favor of a rethought design when generics are completed.

In their current form, varargs are fairly limited—because they're mapped onto an array, the argument types must be homogeneous, so either your function can only usefully take a single type of argument, or you potentially lose information because they have to be upcast to a common supertype or Any in order to build the array.

I'm not convinced that varargs produce code that is much cleaner than the array version. Is this:

String(format: "%@ is %d years old", name, age)

that much cleaner than:

String(format: "%@ is %d years old", arguments: [name, age])

I would like to see format strings go away and be replace with safer inline annotations.

-- E, somewhat agnostic on variadics

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Tino) #13

Why not remove varargs altogether from Swift, it is easy enough to put [] round a list?

+1
I think it's much less useful than tuple-splat, Swifts array-syntax is very lightweight and "…" adds complexity that is rarely needed.


(Tony Allevato) #14

Part of me regrets using String(format:) as my go to example of a varargs
invocation now. :slight_smile:

But while the train is off the rails, why introduce a special syntax at
all? Since interpolation can include any expression, users can just write
small formatting functions and call them there.

Pros: We can standardize a few in stdlib, and it would be more extensible
than learning yet another string formatting language.
Cons: Likely to be more verbose than printf-like descriptors.

···

On Mon, Apr 18, 2016 at 12:27 PM Erica Sadun via swift-evolution < swift-evolution@swift.org> wrote:

This is why god gave us bike sheds.

Maybe "My earned interest rate this year is \({02.2}theRate)%!"

-- E

> On Apr 18, 2016, at 1:23 PM, Ricardo Parada <rparada@mac.com> wrote:
>
> What would that look like?
>
>
>
>> On Apr 18, 2016, at 3:06 PM, Erica Sadun via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>>
>>> On Apr 18, 2016, at 1:01 PM, Tony Allevato via swift-evolution < > swift-evolution@swift.org> wrote:
>>>
>>> I would also be supportive of removing varargs for now, in favor of a
rethought design when generics are completed.
>>>
>>> In their current form, varargs are fairly limited—because they're
mapped onto an array, the argument types must be homogeneous, so either
your function can only usefully take a single type of argument, or you
potentially lose information because they have to be upcast to a common
supertype or Any in order to build the array.
>>>
>>> I'm not convinced that varargs produce code that is much cleaner than
the array version. Is this:
>>>
>>> String(format: "%@ is %d years old", name, age)
>>>
>>> that much cleaner than:
>>>
>>> String(format: "%@ is %d years old", arguments: [name, age])
>>
>> I would like to see format strings go away and be replace with safer
inline annotations.
>>
>> -- E, somewhat agnostic on variadics
>>
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Goffredo Marocchi) #15

Let's build strings the same way we log.... String("\(authorOfAutoLayoutMasterBook) could you please show \(canICountHowMany) times more love to \(ToolThatBuildsInterfaces) :)") :slight_smile: ?

[[iOS messageWithData:ideas] broadcast]

···

On 18 Apr 2016, at 20:06, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 18, 2016, at 1:01 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

I would also be supportive of removing varargs for now, in favor of a rethought design when generics are completed.

In their current form, varargs are fairly limited—because they're mapped onto an array, the argument types must be homogeneous, so either your function can only usefully take a single type of argument, or you potentially lose information because they have to be upcast to a common supertype or Any in order to build the array.

I'm not convinced that varargs produce code that is much cleaner than the array version. Is this:

String(format: "%@ is %d years old", name, age)

that much cleaner than:

String(format: "%@ is %d years old", arguments: [name, age])

I would like to see format strings go away and be replace with safer inline annotations.

-- E, somewhat agnostic on variadics

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dennis Weissmann) #16

- Dennis

I would like to see format strings go away and be replace with safer inline annotations.

The main problem is doing localized strings with printf-style formats well, but I actually have a pretty sweet solution for that: https://gist.github.com/brentdax/79fa038c0af0cafb52dd

-- E, somewhat agnostic on variadics

Variadics are eventually important as a generic function feature; you really want to be able to write a version of zip() which can take any number of sequences, for instance, and the only reasonable way to do that is to pass a variable number of parameters and return a sequence with a matchingly variable number of type parameters.

Which brings us to dependent types :slight_smile:

Today, they are important in that they bootstrap ArrayLiteralConvertible and DictionaryLiteralConvertible by (at least theoretically) acting as a pass-N-items mechanism that doesn't depend on one of the standard library types defined in terms of it. (If we convert them to show up as tuples once we have tuple subscripting syntax, that will even become true.) Less esoterically, they're used in several places where an Array would be inconvenient or break traditions:

* The `print` function's list of items to print is variadic. An array equivalent would look like `print([one, two, three])`.
* The `min` and `max` functions are more convenient than explicitly constructing an array and calling their `min()` and `max()` methods.
* And, yes, `String.init(format:_:)`, which we will probably never be quite rid of for compatibility reasons.

All those points are also perfectly solved by dependent types (which is definitely not in the time frame of Swift 3 or even Swift 4).
But I think in the long term we should get rid of varargs and Swift 3 (as far as I remember) is the last version of Swift to remove functionality from the language (is that actually correct?).

Short-term solutions:

I very very rarely use the print function with multiple parameters. Most of the time I build a single string and use string interpolation to insert values. If there really is a need for multiple arguments to print, like others said, overloads could be generated.
min and max: I think most the time they are used to compare 2 values. If there are more than 2 values (or let’s say 3) I think an array is better suited.
String.init(format:_:slight_smile: … I think if all C APIs would get imported by converting varargs to arrays we could get rid of it.

···

On Apr 18, 2016, at 9:55 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


#17

Oh no please no. Of course a variadic function can always be rewritten as a function that takes an array. Of course. You always can use an array. Got it. But some APIs are nicer with varargs. And even nicer APIs go over the top by adding support for arrays too, because not all lists are known at compile time. It’s a matter of being sensible.

  DatabaseTable.select(id, name).order(name, id) // What’s the problem?
  // vs.
  DatabaseTable.select([id, name]).order([name, id]) // OK, of course... But some people will find it a litle short

Gwendal Roué

···

Le 18 avr. 2016 à 09:35, Dennis Weissmann via swift-evolution <swift-evolution@swift.org> a écrit :

Why not remove varargs altogether from Swift, it is easy enough to put [] round a list?

+1, that was my thought too. I can’t think of a use case where you can’t use an array instead of varargs (this assumes all vararg parameters are converted to array parameters).


(Brent Royal-Gordon) #18

All those points are also perfectly solved by dependent types

How? What does print() or max() or ArrayLiteralConvertible have to do with dependent types?

And what makes you think we're going to get dependent types, anyway?

I very very rarely use the print function with multiple parameters. Most of the time I build a single string and use string interpolation to insert values. If there really is a need for multiple arguments to print, like others said, overloads could be generated.

How many? What will that do to the type checker, which can go exponential on the number of overloads?

min and max: I think most the time they are used to compare 2 values. If there are more than 2 values (or let’s say 3) I think an array is better suited.

Why do you think an array is better suited?

String.init(format:_:slight_smile: … I think if all C APIs would get imported by converting varargs to arrays we could get rid of it.

Are you sure that's actually possible?

And ultimately, why are you so eager to remove this feature? Is there something wrong with it?

···

--
Brent Royal-Gordon
Architechies


(Thorsten Seitz) #19

Just annotenhere: String intepolation is ok for logging purposes but not for creating user messages which have to be localized (with possibly having to reorder the parameters).

-Thorsten

···

Am 18.04.2016 um 22:56 schrieb Dennis Weissmann via swift-evolution <swift-evolution@swift.org>:

- Dennis

On Apr 18, 2016, at 9:55 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

I would like to see format strings go away and be replace with safer inline annotations.

The main problem is doing localized strings with printf-style formats well, but I actually have a pretty sweet solution for that: https://gist.github.com/brentdax/79fa038c0af0cafb52dd

-- E, somewhat agnostic on variadics

Variadics are eventually important as a generic function feature; you really want to be able to write a version of zip() which can take any number of sequences, for instance, and the only reasonable way to do that is to pass a variable number of parameters and return a sequence with a matchingly variable number of type parameters.

Which brings us to dependent types :slight_smile:

Today, they are important in that they bootstrap ArrayLiteralConvertible and DictionaryLiteralConvertible by (at least theoretically) acting as a pass-N-items mechanism that doesn't depend on one of the standard library types defined in terms of it. (If we convert them to show up as tuples once we have tuple subscripting syntax, that will even become true.) Less esoterically, they're used in several places where an Array would be inconvenient or break traditions:

* The `print` function's list of items to print is variadic. An array equivalent would look like `print([one, two, three])`.
* The `min` and `max` functions are more convenient than explicitly constructing an array and calling their `min()` and `max()` methods.
* And, yes, `String.init(format:_:)`, which we will probably never be quite rid of for compatibility reasons.

All those points are also perfectly solved by dependent types (which is definitely not in the time frame of Swift 3 or even Swift 4).
But I think in the long term we should get rid of varargs and Swift 3 (as far as I remember) is the last version of Swift to remove functionality from the language (is that actually correct?).

Short-term solutions:

I very very rarely use the print function with multiple parameters. Most of the time I build a single string and use string interpolation to insert values. If there really is a need for multiple arguments to print, like others said, overloads could be generated.
min and max: I think most the time they are used to compare 2 values. If there are more than 2 values (or let’s say 3) I think an array is better suited.
String.init(format:_:slight_smile: … I think if all C APIs would get imported by converting varargs to arrays we could get rid of it.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dennis Weissmann) #20

That’s IMO already a problematic case:

  DatabaseTable.select(id, name).order(name, id) // What’s the problem?
  // vs.
  DatabaseTable.select([id, name]).order([name, id]) // OK, of course... But some people will find it a litle short

The problem is that you can’t tell by looking at the call site whether `select` takes an id and a name as parameter (the function being declared as `func select(id: String, _ name: String)` or a vararg `func select(string: String…)`.
Both call sites look like this:

select(id, name)

I think it would make the language clearer and more consistent if varargs were removed.

- Dennis

···

On Apr 18, 2016, at 9:48 AM, Gwendal Roué <gwendal.roue@gmail.com> wrote:

Le 18 avr. 2016 à 09:35, Dennis Weissmann via swift-evolution <swift-evolution@swift.org> a écrit :

Why not remove varargs altogether from Swift, it is easy enough to put [] round a list?

+1, that was my thought too. I can’t think of a use case where you can’t use an array instead of varargs (this assumes all vararg parameters are converted to array parameters).

Oh no please no. Of course a variadic function can always be rewritten as a function that takes an array. Of course. You always can use an array. Got it. But some APIs are nicer with varargs. And even nicer APIs go over the top by adding support for arrays too, because not all lists are known at compile time. It’s a matter of being sensible.

  DatabaseTable.select(id, name).order(name, id) // What’s the problem?
  // vs.
  DatabaseTable.select([id, name]).order([name, id]) // OK, of course... But some people will find it a litle short

Gwendal Roué