array splatting for variadic parameters


(Dimitri Racordon) #1

Hello everyone.

I understand that topic has already been discussed in the past, but I failed to get any information on its current state of affairs.

I guess the subject of this mail is explicit, but to make sure I’m clear, here's a small snippet that illustrates the problem:

func f(args: Int…) {
  // Some implementation ...
}
// Now it's impossible to call f without explicitly naming its parameters.

For many use-cases, this problem can be solved by overloading f so that it explicitly accepts an array.

func f(_ args: [Int]) {
  // Some implementation ...
}

func f(_ args: Int…) {
  f(args)
}

Some people also advocate (myself generally included) that one should prefer the signature explicitly marking args as an array, as the syntactic overhead of wrapping the arguments with “[]” when calling f is arguably bearable. However, in some other situations, this approach might not be applicable. For instance, one may simply not be able to modify the original function. Another use-case may be a function that should forward its own variadic parameters.

In a variety of other languages, there exists a way to do this. For instance, Python can “unpack” (or splat) a list into function arguments by prefixing it with *:

def f(*args):
  # Some implementation …

f(*[1, 2, 3]) # == f(1, 2, 3)

I was wondering if such feature could be supported by Swift, and if not, why.

Syntactically, I like the use of “…”, which would mirror function signatures:

f(…[1, 2, 3]) // == f(1, 2, 3)

Thanks.

···

--
Dimitri Racordon


(Slava Pestov) #2

Hi Dimitri,

I think this is a desirable feature, but nobody has got around to designing and implementing it yet.

Another case where it comes up is initializer inheritance. Suppose I have:

class Base {
  init(x: Int…) {}
}

class Derived : Base {
}

Currently, Derived does not inherit Base.init(), because we have no way to synthesize the AST which performs this ‘forwarding’.

In fact, if somebody wanted to attempt an implementation of this, handling this case first would be easier because then you can implement the AST node for splatting a vararg and get it working without worrying about parser changes (probably you can shoehorn it into TupleShuffleExpr). Then after a design for the syntax has been accepted, add the parser support on top.

Slava

···

On Feb 9, 2017, at 3:51 PM, Dimitri Racordon via swift-evolution <swift-evolution@swift.org> wrote:

Hello everyone.

I understand that topic has already been discussed in the past, but I failed to get any information on its current state of affairs.

I guess the subject of this mail is explicit, but to make sure I’m clear, here's a small snippet that illustrates the problem:

func f(args: Int…) {
  // Some implementation ...
}
// Now it's impossible to call f without explicitly naming its parameters.

For many use-cases, this problem can be solved by overloading f so that it explicitly accepts an array.

func f(_ args: [Int]) {
  // Some implementation ...
}

func f(_ args: Int…) {
  f(args)
}

Some people also advocate (myself generally included) that one should prefer the signature explicitly marking args as an array, as the syntactic overhead of wrapping the arguments with “[]” when calling f is arguably bearable. However, in some other situations, this approach might not be applicable. For instance, one may simply not be able to modify the original function. Another use-case may be a function that should forward its own variadic parameters.

In a variety of other languages, there exists a way to do this. For instance, Python can “unpack” (or splat) a list into function arguments by prefixing it with *:

def f(*args):
  # Some implementation …

f(*[1, 2, 3]) # == f(1, 2, 3)

I was wondering if such feature could be supported by Swift, and if not, why.

Syntactically, I like the use of “…”, which would mirror function signatures:

f(…[1, 2, 3]) // == f(1, 2, 3)

Thanks.

--
Dimitri Racordon

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


(Tino) #3

func f(_ args: [Int]) {
  // Some implementation ...
}

func f(_ args: Int…) {
  f(args)
}

Some people also advocate (myself generally included) that one should prefer the signature explicitly marking args as an array, as the syntactic overhead of wrapping the arguments with “[]” when calling f is arguably bearable. However, in some other situations, this approach might not be applicable. For instance, one may simply not be able to modify the original function. Another use-case may be a function that should forward its own variadic parameters.

There has been a proposal that would not only solve this issue, but also add a lot flexibility while simplifying the language at the same time:
https://github.com/Haravikk/swift-evolution/blob/a13dc03d6a8c76b25a30710d70cbadc1eb31b3cd/proposals/nnnn-variadics-as-attribute.md

Imho it's one of the best ideas I have seen on evolution, and definitely the most valuable segregation of C legacy.
Sadly, it was discussed in a very busy timeframe, and I think it really didn't receive the attention it deserves…

I would have asked Haravikk wether he would like to start a second try anyways, and as this topic is directly related, it's a good motivation to do so.

The basic idea of the proposal is to get rid of "…"-magic and declare variadic parameters with their natural type (Array<T> — but one aspect of this idea is that it can be extended easily to work with sets and other types that can be expressed with an array literal).


(Dimitri Racordon) #4

The proposal is indeed really interesting.
I would love to see if it could get a second round of discussion.

However, I failed to understand the syntax of the proposed extension. Where would be defined the label and parameter names? Is this just a typo?

func someFunc<I:IteratorProtocol where I.Element == Int)

Thanks,

Dimitri

···

On 11 Feb 2017, at 13:08, Tino Heth <2th@gmx.de<mailto:2th@gmx.de>> wrote:

func f(_ args: [Int]) {
  // Some implementation ...
}

func f(_ args: Int…) {
  f(args)
}

Some people also advocate (myself generally included) that one should prefer the signature explicitly marking args as an array, as the syntactic overhead of wrapping the arguments with “[]” when calling f is arguably bearable. However, in some other situations, this approach might not be applicable. For instance, one may simply not be able to modify the original function. Another use-case may be a function that should forward its own variadic parameters.

There has been a proposal that would not only solve this issue, but also add a lot flexibility while simplifying the language at the same time:
https://github.com/Haravikk/swift-evolution/blob/a13dc03d6a8c76b25a30710d70cbadc1eb31b3cd/proposals/nnnn-variadics-as-attribute.md

Imho it's one of the best ideas I have seen on evolution, and definitely the most valuable segregation of C legacy.
Sadly, it was discussed in a very busy timeframe, and I think it really didn't receive the attention it deserves…

I would have asked Haravikk wether he would like to start a second try anyways, and as this topic is directly related, it's a good motivation to do so.

The basic idea of the proposal is to get rid of "…"-magic and declare variadic parameters with their natural type (Array<T> — but one aspect of this idea is that it can be extended easily to work with sets and other types that can be expressed with an array literal).


(Anton Zhilin) #5

The proposal is indeed really interesting.

I would love to see if it could get a second round of discussion.

However, I failed to understand the syntax of the proposed extension.
Where would be defined the label and parameter names? Is this just a typo?

func someFunc<I:IteratorProtocol where I.Element == Int)

“Obviously”, the Collection variant should look like:

func someFunc<C: Collection where C.Iterator.Element == Int>(_ values:
@variadic C) { … }

And the others are analagous.

···

2017-02-14 18:32 GMT+03:00 Dimitri Racordon via swift-evolution < swift-evolution@swift.org>:


(Haravikk) #6

Thanks for the correction, not entirely sure how that mistake made it into the proposal!

I didn't get an especially positive response to the proposal at the time, but it is still very much my preferred solution.

"Splatting" as the OP suggests is a simpler solution, but leaves variadics limited to a unique syntax with no control over type; I'm also not keen on re-using ellipsis as an operator for it, since it's also used for handling ranges, though that's not a major overlap. But still, part of why I made my proposal is that splatting feels more like a workaround to a problem of there not being a proper array/sequence/etc. signature for the function.

I could of course be biased, but then I've never really supported variadics as a feature in the first place :smirk:

···

On 14 Feb 2017, at 20:43, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

2017-02-14 18:32 GMT+03:00 Dimitri Racordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

The proposal is indeed really interesting.
I would love to see if it could get a second round of discussion.

However, I failed to understand the syntax of the proposed extension. Where would be defined the label and parameter names? Is this just a typo?

func someFunc<I:IteratorProtocol where I.Element == Int)

“Obviously”, the Collection variant should look like:

func someFunc<C: Collection where C.Iterator.Element == Int>(_ values: @variadic C) { … }
And the others are analagous.


(Dimitri Racordon) #7

"Splatting" as the OP suggests is a simpler solution, but leaves variadics limited to a unique syntax with no control over type;

I also your prefer the proposal than my initial suggestion.

I could of course be biased, but then I've never really supported variadics as a feature in the first place :smirk:

To be perfectly honest, I’m not the biggest zealot of variadics neither =D

However, I spend most of my time writing libraries for people unfamiliar with programming, or even computer science in general. As a result, I often provide them with "domain specific languages” embedded in some host language. Swift fits that job extremely well, thanks to many of its features; variadics are one of them.


(Tino) #8

I didn't get an especially positive response to the proposal at the time, but it is still very much my preferred solution.

I'm convinced that the timing had a very huge impact on the reaction:
It was a very busy period, and I had a strong impression that people just wanted to limit the workload for the next milestone.

Imho "…"-variadics are a C-legacy that is a much worse fit for Swift than things that have been abandoned during times with higher motivation for such changes (I'm thinking of the for-loop and the increment/decrement operators).

For me, the change not only removes a strange syntax and type oddity, making Swift easier to understand — it also makes the language more powerful without additional cost.