Generic func 'Cannot convert type (T)->(V)->() to expected type (_)->(_)->()' when V has 2 or more args

Hi Everyone,

I'm having trouble using a generic function

func genericCall<T, Args, Ret>(_ closure: (T) -> (Args) -> Ret,
                               _ t: T,
                               _ args: Args) -> Ret {
  return closure(t)(args)
}

class Test {
  func sum(a:Int, b:Int) -> Int { return a + b }
  func pr(a:Int) { print(a) }
}

let t = Test()
genericCall(Test.sum, t, (2, 4))  // error 
genericCall(Test.pr, t, (1))      // no problem

When the method has more than 1 parameter the compiler err's with 'Cannot convert type (Test)->(Int,Int)-> Int to expected type (_)->(_)->()'

Is this a bug or I'm missing something here? (using Xcode 10.1 (10B61))

Thanks

Argument lists and tuples are not implicitly interchangeable. You are trying to send a single (2, 4) tuple to a function that requires two separate arguments.

You will need to duplicate genericCall for each number of arguments you want to use it with. This would be the two‐argument variant:

func genericCall<T, Arg1, Arg2, Ret>(_ closure: (T) -> (Arg1, Arg2) -> Ret,
                               _ t: T,
                               _ args: (Arg1, Arg2)) -> Ret {
    return closure(t)(args.0, args.1)
}

Thanks, I've read about Tuple Splat and though that it was still on the language, but forgot that it is removed.

1 Like

From the end of SE-0029:

The major problem with this feature is that it was not well considered and implemented properly [...]. As such, the alternative is to actually design a proper feature to support this. [...] If there is serious interest in pursuing this as a concept, we should do it as a follow-on proposal to this one. If a good design emerges, we can evaluate that design based on its merits.

Do you have any thoughts on the matter other than wishing you could still use it?

I was just wishing to use it.. but your question made me think about it...

Having it could lead to some interesting APIs to pop up (like something I was doing, in having an extension of an object to be able to call into a method of another without much roundtrips).
For this to happen I think a good place to start is to attribute the closure/func/method of being able to receive it's parameters in a tuple, like

@mergableparams func mayTupledArgsFunc(_ a: Int, _ b: String) { }
...
mayTupledArgsFunc(42, "Hello World!") // or..
let args = (42, "Hello World!")
mayTupledArgsFunc(args) 

But as previously said, it's a sugar feature and also I found a "workaround" already.
It was just that I was thinking in a maybe less verbose way to do it (although I didn't like much the use of the tuple in genericCall anyway...)