[Pitch N+1] Typed Throws

This is absolutely right. See the past discussion here: Pitch: Fix rethrows checking and add rethrows(unsafe)

Fixing the soundness hole with rethrows Classicâ„¢ is a source break, and requires a new escape hatch mechanism to make certain idioms work:

func f(fn: () throws -> T) rethrows {
  var result: Result<T, Error>? = nil
  someNonThrowingThing {
    do {
      result = .success(try fn())  // call to conditionally-throwing closure here
    } catch {
      result = .failure(error)
  }

  try result.get() // this throws unconditionally from the type checker's POV
}

Several libraries already use the local function workaround to make the above type check, so we'd need a rethrows(unsafe) to express it, but that's gross.

With typed throws, you don't need the escape hatch at all. Parameterizing everything over E expresses this idiom safely:

func f<T, E>(fn: () throws(E) -> T) throws(E) {
  var result: Result<T, E>? = nil
  someNonThrowingThing {
    do {
      result = .success(try fn())  // call to closure that throws E
    } catch {
      result = .failure(error)
  }

  try result.get() // if this throws, it throws E, so it's fine
}

So in my opinion, we should freeze rethrows as-is, and not try to invent a rethrows(E) for typed throws.

7 Likes