[Concurrency] Continuations for interfacing async tasks with synchronous code

Can the continuation APIs be nested within the Result enum?

  • The Success and Failure types won't need to be inferred.
  • There's no need for separate throwing and non-throwing APIs.
extension Result {

  public struct UnsafeContinuation {

    // Or use `callAsFunction(_:)` instead?
    public func resume(_ result: Result)
  }

  public static func withUnsafeContinuation(
    _ body: (UnsafeContinuation) -> Void
  ) async -> Self
}

Example:

extension Data {

  init(asyncContentsOf url: URL) async throws {
    let result = await Result<Data, Error>.withUnsafeContinuation {
      continuation in
      let request = URLRequest(url: url)
      let task = URLSession.shared.dataTask(with: request) {
        data, _, error in
        if let error = error {
          continuation.resume(.failure(error))
        } else {
          continuation.resume(.success(data ?? Data()))
        }
      }
      task.resume()
    }
    self = try result.get()
  }
}

To avoid forced try!, a non-throwing API could also be added:
(But it would be source-breaking with -warnings-as-errors.)

extension Result where Failure == Never {

  public func get() -> Success {
    switch self {
    case .success(let success):
      return success
    }
  }
}
2 Likes