Variadic Parameters that Accept Array Inputs

I'm for manual splatting.

Do you think that you should be able to splat any Collection?

Array splatting is the big win here, and moving from only being able to splat arrays to being able to splat arbitrary collections isn't source breaking, so I think we should leave out the more general version unless we have an actual use case for it.

I don’t think we should support all Collections. Supporting Array has no performance impact, since variadic arguments are already passed in an Array. Supporting all Collections means constructing a temporary Array (costs in performance) or redesigning variadic arguments to support any Collection (costs in design time, implementation time, and probably performance too).

3 Likes

I second this, for a different reason:

We have to assume that parameter order matters, even for variadic functions. Giving the ability to splat non-ordered collections will just lead to bugs that would otherwise be really obvious to avoid.

4 Likes

We should also ensure that an error message is thrown if someone does indeed input a variable holding Variadic<Int> that they need to splat it before putting it into a parameter holding Int... (Variadic<Int>).

Why would it be an error? Perhaps I'm missing something, but wouldn't Variadic, as proposed, be a fully-qualified type? Why would it be restricted in this way?

2 Likes

So @Avi, would you say that the only circumstances that require manual splatting should be those where the variadic parameter itself cannot hold a variadic values (check the following example)

// for the purpose of the argument,`doSomethingWithAnyCollection` or `doSomethingWithACollection <T: Collection>(_ arg: T)`
func doSomethingWithAny(_ arg: VariadicArray<Any>) { // could have also wrote Any...

    let count = arg.count
    print(count)
}

What would you say should happen if I do this:

let slightlyProblematicVariadic : VariadicArray<Any> = [3, true, "Marvin", "Sally", -12439.2349332, false]

doSomethingWithAny(slightlyProblematicVariadic)

What should be printed, 1 or 6?

What about if I do:

let slightlyProblematicVariadic : VariadicArray<Any> = [3, true, "Marvin", "Sally", -12439.2349332, false]
let anotherProblematicVariadic : VariadicArray<Any> = [false, "Joe", 23, "Allan", true, 47.4951]

doSomethingWithAny(slightlyProblematicVariadic, anotherProblematicVariadic)

What should happen in this case too?

The opposite. If the type can hold a variadic, it requires manual splatting to explicitly declare the desired behavior at the call site. If you don't do this, there would be no way to pass a VariadicArray as a single parameter to such methods.

You could make it a rule: VariadicArray is always splatted, and to avoid this, wrap the value in Array() at the call site. But, can this be optimized out at compile time? An explicit splat of VariadicArray is handled at compile time, because it directs the compiler to not wrap the VariadicArray into another VariadicArray. Forcing the call site to invoke Array() would either need special compiler magic, or it would happen at runtime.

I think in this case "6" would be printed, as you are passing a Variadic<Any> to a function taking a Variadic<Any>

In this case, I would say "2" would be printed, as you are passing Variadic<Variadic<Any>> to a function accepting Variadic<Any>.

2 Likes

That's what I would expect, too.

1 Like

Should a parameter of Int… accept a variable holding a VariadicSet<Int> as well as VariadicArray<Int>. But if a variable is not explicitly declared I think that it should be inferred to be a VariadicArray, leaving VariadicSets to require explicit type inference as is the same in the declaration of Sets and Arrays

aRandomVariadic = 1,2,3,4,5,6 //Inferred to be VariadicArray<Int>

Lastly, I think the shorthand, T… should be restricted to use only in functions as parameters that can reference VariadicArrays and VariadicSets. Like the equivalent of writing the hypothetical AnyVariadic in this case.

1 Like