Generics with variable argument lists


(Rien) #1

I am trying to achieve the following:

enum FunctionResult<T> {
  case success(T)
  case error(String)
}

func tester<T>(test: (…) -> FunctionResult<T>, onError: (String) -> T) -> T {
   …
}

The problem is of course the (…) that simply does not work.

I would like to use this generic with a variety of different signatures, i.e.:

let result1 = tester(test: myfunc1(param: 26) -> FunctionResult<Bool>, onError: { … handle the error ... })
let result2 = tester(test: myfunc2(param: “A String") -> FunctionResult<Bool>, onError: { … handle the error ... })
let result3 = tester(test: myfunc3(param: 26, param2: “String") -> FunctionResult<Int>, onError: { … handle the error ... })

Is this at all possible?

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl


(Ole Begemann) #2

This should do it:

     func tester<T>(test: @autoclosure () -> FunctionResult<T>,
         onError: (String) -> T) -> T {
         switch test() {
         case .success(let value): return value
         case .error(let error): return onError(error)
         }
     }

The insight is that you don't really want to pass a function in the first parameter, but only the _result_ of that function call. The @autoclosure attribute then makes sure that the expression you pass to tester is only evaluated inside tester. You can leave it out if you want (if you do, replace `switch test()` with `switch test`).

···

On 09/03/2017 11:05, Rien via swift-users wrote:

I am trying to achieve the following:

enum FunctionResult<T> {
  case success(T)
  case error(String)
}

func tester<T>(test: (…) -> FunctionResult<T>, onError: (String) -> T) -> T {
   …
}

The problem is of course the (…) that simply does not work.

I would like to use this generic with a variety of different signatures, i.e.:

let result1 = tester(test: myfunc1(param: 26) -> FunctionResult<Bool>, onError: { … handle the error ... })
let result2 = tester(test: myfunc2(param: “A String") -> FunctionResult<Bool>, onError: { … handle the error ... })
let result3 = tester(test: myfunc3(param: 26, param2: “String") -> FunctionResult<Int>, onError: { … handle the error ... })

Is this at all possible?


(Rien) #3

Ah!, yes that would be perfect!

Many thanks!

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

···

On 09 Mar 2017, at 12:36, Ole Begemann <ole@oleb.net> wrote:

On 09/03/2017 11:05, Rien via swift-users wrote:

I am trying to achieve the following:

enum FunctionResult<T> {
case success(T)
case error(String)
}

func tester<T>(test: (…) -> FunctionResult<T>, onError: (String) -> T) -> T {
  …
}

The problem is of course the (…) that simply does not work.

I would like to use this generic with a variety of different signatures, i.e.:

let result1 = tester(test: myfunc1(param: 26) -> FunctionResult<Bool>, onError: { … handle the error ... })
let result2 = tester(test: myfunc2(param: “A String") -> FunctionResult<Bool>, onError: { … handle the error ... })
let result3 = tester(test: myfunc3(param: 26, param2: “String") -> FunctionResult<Int>, onError: { … handle the error ... })

Is this at all possible?

This should do it:

   func tester<T>(test: @autoclosure () -> FunctionResult<T>,
       onError: (String) -> T) -> T {
       switch test() {
       case .success(let value): return value
       case .error(let error): return onError(error)
       }
   }

The insight is that you don't really want to pass a function in the first parameter, but only the _result_ of that function call. The @autoclosure attribute then makes sure that the expression you pass to tester is only evaluated inside tester. You can leave it out if you want (if you do, replace `switch test()` with `switch test`).