[swift-evolution] [Concurrency] async/await + actors

Karim Nassar karim at karimnassar.com
Mon Aug 21 15:08:57 CDT 2017


Thought about it in more depth, and I’m now firmly in the camp of: ‘throws’/‘try' and ‘async’/‘await' should be orthogonal features. I think the slight call-site reduction in typed characters ('try await’ vs ‘await’) is heavily outweighed by the loss of clarity on all the edge cases.

—Karim

> On Aug 21, 2017, at 1:56 PM, John McCall <rjmccall at apple.com> wrote:
> 
>> 
>> On Aug 20, 2017, at 3:56 PM, Yuta Koshizawa <koher at koherent.org <mailto:koher at koherent.org>> wrote:
>> 
>> 2017-08-21 2:20 GMT+09:00 John McCall via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>:
>>> On Aug 19, 2017, at 7:17 PM, Chris Lattner via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>> On Aug 19, 2017, at 8:14 AM, Karim Nassar via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>> 
>>>> This looks fantastic. Can’t wait (heh) for async/await to land, and the Actors pattern looks really compelling.
>>>> 
>>>> One thought that occurred to me reading through the section of the "async/await" proposal on whether async implies throws:
>>>> 
>>>> If ‘async' implies ‘throws' and therefore ‘await' implies ‘try’, if we want to suppress the catch block with ?/!, does that mean we do it on the ‘await’ ? 
>>>> 
>>>> guard let foo = await? getAFoo() else {  …  }
>>> 
>>> Interesting question, I’d lean towards “no, we don’t want await? and await!”.  My sense is that the try? and try! forms are only occasionally used, and await? implies heavily that the optional behavior has something to do with the async, not with the try.  I think it would be ok to have to write “try? await foo()” in the case that you’d want the thrown error to turn into an optional.  That would be nice and explicit.
>> 
>> try? and try! are quite common from what I've seen.
>> 
>> As analogous to `throws` and `try`, I think we have an option that `await!` means blocking.
>> 
>> First, if we introduce something like `do/catch` for `async/await`, I think it should be for blocking. For example:
>> 
>> ```
>> do {
>>   return await foo()
>> } block
>> ```
>> 
>> It is consistent with `do/try/catch` because it should allow to return a value from inside `do` blocks for an analogy of `throws/try`.
>> 
>> ```
>> // `throws/try`
>> func foo() -> Int {
>>   do {
>>     return try bar()
>>   } catch {
>>     ...
>>   }
>> }
>> 
>> // `async/await`
>> func foo() -> Int {
>>   do {
>>     return await bar()
>>   } block
>> }
>> ```
>> 
>> And `try!` is similar to `do/try/catch`.
>> 
>> ```
>> // `try!`
>> let x = try! foo()
>> // uses `x` here
>> 
>> // `do/try/catch`
>> do {
>>   let x = try foo()
>>   // uses `x` here
>> } catch {
>>   fatalError()
>> }
>> ```
>> 
>> If `try!` is a sugar of `do/try/catch`, it also seems natural that `await!` is a sugar of `do/await/block`. However, currently all `!` in Swift are related to a logic failure. So I think using `!` for blocking is not so natural in point of view of symbology.
>> 
>> Anyway, I think it is valuable to think about what `do` blocks for `async/await` mean. It is also interesting that thinking about combinations of `catch` and `block` for `async throws` functions: e.g. If only `block`, the enclosing function should be `throws`.
> 
> Personally, I think these sources of confusion are a good reason to keep the feature separate.
> 
> The idea of using await! to block a thread is interesting but, as you say, does not fit with the general meaning of ! for logic errors.  I think it's fine to just have an API to block waiting for an async operation, and we can choose the name carefully to call out the danger of deadlocks.
> 
> John.
> 
>> 
>> That aside, I think `try!` is not so occasional and is so important. Static typing has limitations. For example, even if we has a text field which allows to input only numbers, we still get an input value as a string and parsing it may fail on its type though it actually never fails. If we did not have easy ways to convert such a simple domain error or a recoverable error to a logic failure, people would start ignoring them as we has seen in Java by `catch(Exception e) {}`. Now we have `JSONDecoder` and we will see much more `try!` for bundled JSON files in apps or generated JSONs by code, for which decoding fails as a logic failure.
>> 
>> --
>> Yuta

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170821/3beedbe7/attachment.html>


More information about the swift-evolution mailing list