A quick search only got me the following StackOverflow question but it was an XY problem so while OP's problem was solved the question remains unanswered.
I'm finding myself in the same situation but I cannot modify the types. It boils down to the following simplified example:
func call<each Arg, Result, Failure>(
_ f: (repeat each Arg) throws(Failure) -> Result,
with args: (repeat each Arg)
) throws(Failure) -> Result {
// ???
}
I have a tuple with the arguments of a function which expects multiple arguments. I would need to spread the tuple into the arguments of the function.
I believe Swift used to be able to pass a tuple as arguments but it was removed.
I was thinking of a prefix operator on tuples that would turn it into a parameter pack, then you can use it like any other parameter packs.
I used ... here just to stay similar to parameter packs, it could be something else or even a built-in free function.
func f(_ one: Int, _ two: Int, _ three: Int) {}
let tuple = (1,2,3)
f(repeat each ...tuple)
That operator would have a signature of prefix operator ...<each T>(tuple: (repeat each T)) -> each T, this isn't valid Swift as of now as the parameter packs cannot be return values.
You will need both overloads, and also need to provide args as a constant, instead of a variable, unless you fix the compiler.
I had tried repeat each args in my larger project but since it was in a struct I thought it wasn't intended to work, thank you for confirming that it does! Means we don't need an extra operator or whatnot!
I didn't need both overload (if Failure == Never then call won't require try) but I did identify that the crash only occurs when a struct is involved.
func call<each Arg, Result, Failure>(
_ f: (repeat each Arg) throws(Failure) -> Result,
with args: (repeat each Arg)
) throws(Failure) -> Result {
try f(repeat each args)
}
func test(x:Int,y:Int,z:Int) -> String {
"\(x),\(y),\(z)"
}
print(call(test, with: (1,2,3)))
// if I add the following then swiftc crashes.
struct Executer<each Arg, Result, Failure: Error> {
let task: (repeat each Arg) throws(Failure) -> Result
func execute(with args: (repeat each Arg)) throws(Failure) {
try call(task, with: args)
}
}
print(Executer(task: test).execute(with: (2,3,5)))
I can't reproduce the problem now with call now. But it was happening as I was testing, and is sometimes a problem with other signatures, like that splat.
E.g. This crashes the compiler if you don't use the error-less overload.
Don’t we have an according “problem” with variadic parameters vs. arrays, what would an analogous solution be, and should such solutions be part of Foundation? Or should the compiler be very smart instead (if possible)? I am not sure if a better option is to just duplicate the function and let one version call the other (as I usually do it).
But as far as I know, there's no way to pump expanded packs into variadic arguments…
I’m not sure how variadic arguments are currently represented by Swift but I’d love if we could pass a sequence directly (like C#) so I wouldn’t have to double my overloads.
That and passing them as a Span rather than an Array for embedded!
For now I just never use them, I don’t think they’re worth the added overload maintenance.