[swift-evolution] [Question] Why does `beginAsync` rethrow errors?

Yuta Koshizawa koher at koherent.org
Tue Nov 7 21:04:14 CST 2017


Although I posted about this topic before, let me post this again
because I think it is important and I have received just few replies.
Sorry if I missed some discussion about it.

In the proposal (
https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619 ),
`beginAsync` has the following signature.

```
func beginAsync(_ body: () async throws -> Void) rethrows -> Void
```

However, I think it is better to forbid `body` to throw errors, that
is to say, to change its signature to the following one.

```
func beginAsync(_ body: () async -> Void) -> Void
```

Even if `beginAsync` allows that `body` throws errors, it can rethrow
ones which are thrown before only first `await` call. In following
cases, `beginAsync` just has to make the program crash when `foo`
throws an error. It breaks safety for error handing by typed
propagation realized by `throws/try`.

```
// throws errors asynchronously
func foo() async throws -> Int { ... }

do {
    beginAsync {
        let a = try await foo()
        // uses `a` here
    }
} catch _ {
    // never reaches here
}
```

If `beginAsync` forbid `body` to throw errors, it can be detected as a
compilation error and is possible to fix it as follows.

```
beginAsync {
    do {
        let a = try await foo()
        // uses `a` here
    } catch _ {
        //  error handling
    }
}
```

And even when we want to write `try` calls in `beginAsync` before
first `await` call, those lines can be moved before the `beginAsync`
call.

```
// before ( `beginAsync` marked with `rethrows` )
do {
    beginAsync {
        let a = try bar()
        let b = try baz()
        let c = await qux(a, b)
        // uses `c` here
    }
catch _ {
    // error handling
}

// after ( `beginAsync` without `rethrows` )
do {
    let a = try bar()
    let b = try baz()
    beginAsync {
        let c = await qux(a, b)
        // uses `c` here
    }
catch _ {
    // error handling
}
```

So the functionalities of `beginAsync` seems be kept even if it forbid
`body` to throw errors.

What do you think about it?

--
Yuta


More information about the swift-evolution mailing list