5

As far as I understand, rethrows essentially creates two functions from a single declaration/definition, like so:

func f(_ c: () throws -> Void) rethrows { try c()}

// has the same effect as declaring two seperate functions, with the same name:

func g(_ c: () throws -> Void) throws { try c() }
func g(_ c: () -> Void) { c() }

If I have a rethrowing function, like f, is there way to save it as a closure in it's "non-throwing" form? Hypothetically, like so:

let x: (() -> Void) -> Void = f
// invalid conversion from throwing function of type '(() throws -> Void) throws -> ()' to non-throwing function type '(() -> Void) -> Void'

x{ print("test") } // "try" not necessary, because x can't throw
Alexander
  • 59,041
  • 12
  • 98
  • 151
  • 1
    Does `let x: (() -> Void) -> Void = { f($0) }` count as a solution? It is not the same closure, but a wrapper. – Martin R Apr 09 '17 at 07:35
  • @MartinR I suppose so, yeah. I find it odd that there isnt (that I'm aware of) a type relationship that allows this assignment – Alexander Apr 09 '17 at 07:36
  • You may be interested to know that the compiler actually only creates a single overload for a `rethrows` function – one that `throws`. In the case of applying it with a closure that doesn't `throw`, the compiler simply discounts the possibility of the function returning an error. Therefore I suspect there's no easy way to get the non-throwing form – a closure wrapper is probably the best solution. – Hamish Apr 09 '17 at 08:16
  • @Hamish Hah, that's how I figured it would be implemented. But it's a shame there isn't an automated mechanism for accommodating this (such as introducing the extra wrapper automatically) – Alexander Apr 09 '17 at 08:17
  • @Alexander Yeah, it is a shame :/ There are other cases where you really want the compiler to just write a thunk for you, but it just doesn't currently – one other example that springs to mind is for default parameters, e.g `func foo(_ i: Int = 3) {}; let bar: () -> Void = foo`. – Hamish Apr 09 '17 at 08:26
  • @Hamish Ah yeah, that would be nice. For example, for being able to do `...forEach(print)` instead of `...forEach{ print($0) }` – Alexander Apr 09 '17 at 08:28

1 Answers1

3

Until someone comes up with a better solution: Use a wrapper

func f(_ c: () throws -> Void) rethrows { try c() }

let x: (() -> Void) -> Void = { f($0) }
Alexander
  • 59,041
  • 12
  • 98
  • 151
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382