/*:#localized(key: "ErrorsAsyncThrowsAndTryAwait")
 # Errors: `async throws` and `try await`

 Remember how painful errors were in callback code (in chapter [Why Modern Concurrency](Why%20Modern%20Concurrency.playgroundchapter/Overview))? You couldn't
 `throw` (the function had already returned) so you threaded a `Result` or an
 extra `Error?` parameter through every closure, and hoped no code path
 forgot to call the completion handler.

 Async functions throw the *normal* way. Mark the function `async throws`,
 call it with `try await`, and wrap it in an ordinary `do-try-catch`:
 */
//#-editable-code
import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

enum BarError: Error {
    case outOfBeans
}

func grind(grams: Int) async throws -> String {
    try await Task.sleep(for: .milliseconds(500))   // the grinder runs
    guard grams > 0 else { throw BarError.outOfBeans }
    return "Ground \(grams) g of beans"
}

Task {
    do {
        let good = try await grind(grams: 18)
        print(good)

        let bad = try await grind(grams: 0)   // this line throws
        print(bad)                            // ...so we never reach here
    } catch BarError.outOfBeans {
        print("⚠️ Refill the hopper and try again")
    } catch {
        print("Unexpected error: \(error)")
    }
    PlaygroundPage.current.finishExecution()
}
//#-end-editable-code
/*:#localized(key: "ErrorsAsyncThrowsAndTryAwait-2")
 Read that top to bottom: grind, print, grind, print (with a single
 `do-try-catch` around the lot). No nested closures, no `Result`, no
 forgotten callbacks. An error thrown deep in an async call unwinds to your
 `catch` just like a synchronous throw.

 **Watch it run:** you'll see `Ground 18 g of beans`, then about half a
 second later `⚠️ Refill the hopper and try again`. The second `print` never
 runs, because `try await grind(grams: 0)` threw and jumped straight to the
 matching `catch`.

 > **`try await` order:** write `try` first, then `await`
 > (`try await grind(...)`). Think "try to await this."

 [Previous](@previous)  |  page 6 of 8  |  [Next: Running Work Concurrently with Async Let](@next)
 */
