2017-11-12 2:57 GMT+09:00 Adam Kemp <adam.k...@apple.com>: > > >> On Nov 11, 2017, at 6:24 AM, Yuta Koshizawa <ko...@koherent.org> wrote: >> >> If you replace `async` with `throws`, you can get answers. >> >> >>> Can you declare an async closure variable? >> >> Yes. Like `let throwingClosure:() throws -> Void = { ... }`. >> >> >>> Can a non-async closure be passed to a function expecting a async closure? >> >> Yes. Like we can pass `() -> Void` to a function expecting a throwing >> closure `() throws -> Void`. >> >> It is possible because `(Foo) throws -> Bar` is a supertype of `(Foo) >> -> Bar`. `(Foo) async -> Bar` is a supertype of `(Foo) -> Bar` in the >> same way. >> >> To treat an async function as a sync function is legal. It is similar >> to make a `Promise` by `Promise(value)` which is completed >> immediately. >> >> >>> Can an async closure be passed to a function expecting a non-async closure? >> >> No. `() -> Void` is a subtype of `() async -> Void`. It is same as >> passing `() throws -> Void` to a function expecting `() -> Void` is >> not allowed. > > But why not? Just asserting that it must work the same as throws > is not a convincing argument. You have to justify why it must work > that way. I think there is good reason to allow it, which I have described. > What reason is there to disallow it?
`() async -> Void` needs to be called with `await` because it prevents us from forgetting handling asynchronous operations. If we use callbacks to handle asynchronous operations, it is shown to us by a compiler as a compilation error. ``` func fooAsync(_ handler: () -> Void) -> Void { ... } fooAsync() // compilation error fooAsync { // handles a completion event here } ``` With proposed `async/await`, it is realized similarly like below. ``` func fooAsync() async -> Void { ... } fooAsync() // compilation error await fooAsync() // handles a completion event here ``` However, if async void functions work like `beginAsync`, we can easily forget it and it can cause unexpected behaviors. ``` func fooAsync() async -> Void { ... } fooAsync() // OK // hard to know this line is executed asynchronously ``` Readability also suffers seriously. If we don't know `bar` in the following code is a async function, it is impossible to expect lines after `baz()` are executed asynchronously. ``` foo() bar() baz() qux() ``` >>> It’s weird to me that we would allow you to have async void closures but >>> not async void functions >> >> I am not sure what you mean. "async void closures" and "async void >> functions" have a same type. Following two are almost same. >> >> ``` >> func foo() async -> Void { ... } >> let foo: () async -> Void = { ... } >> ``` > > What started this thread is my suggestion that you should be able to write > an async void function. The current proposal doesn’t allow that. That’s why > you have to use beginAsync. > > I don’t think that makes sense. It sounds like you also think that would be > strange, > hence your assumption that you could. By the reasons I wrote above, we need `await` even for async void functions for checks by compilers. Then it is required to provide a way to write entry points of async functions. That is `beginAsync`. -- Yuta _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution