However, equally important to the case I was making earlier is that you should be able to call an “async Never” function as if it were a non-async Void function. This is especially important for cases where you want to pass a callback to something (like an event handler), and you want the callback to be able to use await. So as long as that still works I could live with "async Never”.
> On Nov 13, 2017, at 9:49 AM, Adam Kemp <adam_k...@apple.com> wrote: > > I kind of like that idea. I’d rather have a Task/Future/Promise/whatever, but > if that’s not going to happen then Void vs. Never seems like a reasonable way > of distinguishing these two cases. > >> On Nov 12, 2017, at 9:55 AM, Xiaodi Wu <xiaodi...@gmail.com >> <mailto:xiaodi...@gmail.com>> wrote: >> >> Sorry, I'm just getting into this conversation late and am by no means >> experienced in the area, but why can't the one where you *don't* want the >> caller to wait for the result be spelled `async -> Never`? Theoretically, >> `async -> Void` means you're awaiting a result with only one possible value, >> but if you're not waiting at all, then there is truly no result, yes? >> >> >> On Sun, Nov 12, 2017 at 9:27 AM, Yuta Koshizawa via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >> Sorry, I had got some confusion. Please let me retry to explain. >> >> As you said, C# provides three kinds of async functions: `async Void`, >> `async Task` and `async Task<Foo>`. All of them are necessary and >> Swift should provide same functionalities. >> >> When we think about `async/await` in Swift, because we have already >> had `throws/try`, it is desired that `async/await` in Swift is >> consistent with `throws/try`. So it is better to have `async/await` >> without introducing a type like `Task` (or `Promise`). >> >> Even if we employ `async/await` without `Task`, Swift has to provides >> functionalities to implement "three kinds of async functions" in C#. >> However if `async -> Void` in Swift works similarly to `async Void` in >> C#, how can we express ones like `async Task` in C#? I think there are >> two possibilities: >> >> 1. Calling `async -> Void` functions without `await` in Swift works >> like `async Void` in C# and calling them *with* `await` works like >> `async Task` in C#. >> 2. Calling `async -> Void` functions without `await` in Swift works >> like `async Void` in C# and never support something like `async Task` >> in C#. >> >> I think 2 is impermissible. For example, handling completion events of >> asynchronous operations without result values needs something like >> `async Task` in C#. However, with 1, we lose the benefit of static >> checks by the compiler. Because both of `fooAsync()` without `await` >> and `await fooAsync()` are allowed, even if we want it to work like >> `async Task` in C# and forget to mark `await`, the compiler tell us >> nothing and it works like `async Void` in C#. It causes unexpected >> behaviors. It is hard to fix such kinds of bugs. So I think >> introducing `beginAsync` is better. >> >> -- >> Yuta >> >> >> 2017-11-12 10:23 GMT+09:00 Yuta Koshizawa via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>: >> > 2017-11-12 2:57 GMT+09:00 Adam Kemp <adam.k...@apple.com >> > <mailto:adam.k...@apple.com>>: >> >> >> >> >> >>> On Nov 11, 2017, at 6:24 AM, Yuta Koshizawa <ko...@koherent.org >> >>> <mailto: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 <mailto:swift-evolution@swift.org> >> > https://lists.swift.org/mailman/listinfo/swift-evolution >> > <https://lists.swift.org/mailman/listinfo/swift-evolution> >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution