[swift-evolution] Async Affordances Wish List
Marc Schlichte
marc.schlichte at googlemail.com
Fri Aug 11 15:03:14 CDT 2017
Hi,
to help with async programming tasks, I could see the following affordances on async/await to be helpful:
1. Make existing Continuation Passing Style (CPS) APIs available via async/await.
2. Await with timeouts.
3. Possibility to cancel awaits.
To be more specific:
Ad 1.
I think it could be helpful if an API like:
`func foo(_ arg: Arg, completion: (val: Val) -> Void)`
could be invoked like this:
`let val: Val = await foo(arg)`
(i.e, having a mapped signature like: `func foo(_ arg: Arg) async -> Val`)
Often, the completion takes an error argument:
`func bar(_ arg: Arg, completion: (val: Val?, err: Error?) -> Void)`
Calling it via async/await might look like this:
```
do {
let val: Val = try await bar(arg)
} catch {
// handle error
}
```
I could imagine that new type attributes are needed to make this happen:
@continuation: the closure which continues the async control flow
`func bar(_ arg: Arg, completion: @continuation (val: Val?, err: Error?) -> Void)`
This function would transform to something like this:
`func bar(_ arg: Arg) throws async -> Val`
Some developers already have adopted a Result style - it would be nice to support the same conversion here too:
`func bar2(_ arg: Arg, completion: @continuation (result: Result<Val>) -> Void)` ->
`func bar2(_ arg: Arg) throws async -> Val`
Maybe `Result` has to adopt a specific protocol to allow this.
Ad 2 - Await with Timeouts
It could be helpful to have the option to specify how long an await should wait before throwing a timeout error:
```
do {
let val = try await(for: 2.718) bar(arg)
} catch AsyncError.timeout {
// handle timeout
} catch {
// handle other errors
}
```
Ad 3 - Cancelation
Sometimes, I maybe want to cancel an async operation.
```
class C {
var task: CancelableTask<Val>?
func startProcess() {
do {
task = baz(arg)
let val = try await task!
…
} catch AsyncError.cancelation {
// handle cancelation
} catch {
// handle other errors
}
}
func cancelProcess() {
task?.cancel()
}
}
```
To be cancelable, a function needs to support that:
```
func baz(_ arg: Arg) -> CancelableTask<Val> {
let task = CancelableTask<Val>()
let sess = URLSession.dataTask(with: arg.url) { data, resp, err in
// No automatic CPS conversion here as dataTask does not return Void
task.finish(with: data.val)
}
task.onCancellation {
sess.cancel()
}
return task
}
```
`baz` would have an equivalent signature of:
`func baz(_ arg: Arg) throws async cancelable-> Val`
Then, the non-cancellable `bar` function from above could also be written as:
`func bar(_ arg: Arg) -> Task<Val>` (aka. Promise, Future, …)
and the non-throwing `foo` function:
`func foo(_ arg: Arg) -> NonThrowingTask<Val>`
Of course, work on concurrency in Swift has a much bigger scope than this laundry list of
on async/await capabilities.
Cheers
Marc
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170811/d24c7227/attachment.html>
More information about the swift-evolution
mailing list