Skip to content

Instantly share code, notes, and snippets.

@koher
Last active November 8, 2017 02:56
Show Gist options
  • Save koher/bcb0ac8c05a4e43b6c5a40bcac041285 to your computer and use it in GitHub Desktop.
Save koher/bcb0ac8c05a4e43b6c5a40bcac041285 to your computer and use it in GitHub Desktop.

[Question] Why does beginAsync rethrow errors?

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 by typed propagation for error handing 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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment