<div dir="ltr">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?<div><br><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Nov 12, 2017 at 9:27 AM, Yuta Koshizawa via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Sorry, I had got some confusion. Please let me retry to explain.<br>
<br>
As you said, C# provides three kinds of async functions: `async Void`,<br>
`async Task` and `async Task<Foo>`. All of them are necessary and<br>
Swift should provide same functionalities.<br>
<br>
When we think about `async/await` in Swift, because we have already<br>
had `throws/try`, it is desired that `async/await` in Swift is<br>
consistent with `throws/try`. So it is better to have `async/await`<br>
without introducing a type like `Task` (or `Promise`).<br>
<br>
Even if we employ `async/await` without `Task`, Swift has to provides<br>
functionalities to implement "three kinds of async functions" in C#.<br>
However if `async -> Void` in Swift works similarly to `async Void` in<br>
C#, how can we express ones like `async Task` in C#? I think there are<br>
two possibilities:<br>
<br>
1. Calling `async -> Void` functions without `await` in Swift works<br>
like `async Void` in C# and calling them *with* `await` works like<br>
`async Task` in C#.<br>
2. Calling `async -> Void` functions without `await` in Swift works<br>
like `async Void` in C# and never support something like `async Task`<br>
in C#.<br>
<br>
I think 2 is impermissible. For example, handling completion events of<br>
asynchronous operations without result values needs something like<br>
`async Task` in C#. However, with 1, we lose the benefit of static<br>
checks by the compiler. Because both of `fooAsync()` without `await`<br>
and `await fooAsync()` are allowed, even if we want it to work like<br>
`async Task` in C# and forget to mark `await`, the compiler tell us<br>
nothing and it works like `async Void` in C#. It causes unexpected<br>
behaviors. It is hard to fix such kinds of bugs. So I think<br>
introducing `beginAsync` is better.<br>
<br>
--<br>
Yuta<br>
<br>
<br>
2017-11-12 10:23 GMT+09:00 Yuta Koshizawa via swift-evolution<br>
<<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>>:<br>
<div class="HOEnZb"><div class="h5">> 2017-11-12 2:57 GMT+09:00 Adam Kemp <<a href="mailto:adam.kemp@apple.com">adam.kemp@apple.com</a>>:<br>
>><br>
>><br>
>>> On Nov 11, 2017, at 6:24 AM, Yuta Koshizawa <<a href="mailto:koher@koherent.org">koher@koherent.org</a>> wrote:<br>
>>><br>
>>> If you replace `async` with `throws`, you can get answers.<br>
>>><br>
>>><br>
>>>> Can you declare an async closure variable?<br>
>>><br>
>>> Yes. Like `let throwingClosure:() throws -> Void = { ... }`.<br>
>>><br>
>>><br>
>>>> Can a non-async closure be passed to a function expecting a async closure?<br>
>>><br>
>>> Yes. Like we can pass `() -> Void` to a function expecting a throwing<br>
>>> closure `() throws -> Void`.<br>
>>><br>
>>> It is possible because `(Foo) throws -> Bar` is a supertype of `(Foo)<br>
>>> -> Bar`. `(Foo) async -> Bar` is a supertype of `(Foo) -> Bar` in the<br>
>>> same way.<br>
>>><br>
>>> To treat an async function as a sync function is legal. It is similar<br>
>>> to make a `Promise` by `Promise(value)` which is completed<br>
>>> immediately.<br>
>>><br>
>>><br>
>>>> Can an async closure be passed to a function expecting a non-async closure?<br>
>>><br>
>>> No. `() -> Void` is a subtype of `() async -> Void`. It is same as<br>
>>> passing `() throws -> Void` to a function expecting `() -> Void` is<br>
>>> not allowed.<br>
>><br>
>> But why not? Just asserting that it must work the same as throws<br>
>> is not a convincing argument. You have to justify why it must work<br>
>> that way. I think there is good reason to allow it, which I have described.<br>
>> What reason is there to disallow it?<br>
><br>
> `() async -> Void` needs to be called with `await` because it prevents<br>
> us from forgetting handling asynchronous operations.<br>
><br>
> If we use callbacks to handle asynchronous operations, it is shown to<br>
> us by a compiler as a compilation error.<br>
><br>
> ```<br>
> func fooAsync(_ handler: () -> Void) -> Void { ... }<br>
><br>
> fooAsync() // compilation error<br>
><br>
> fooAsync {<br>
> // handles a completion event here<br>
> }<br>
> ```<br>
><br>
> With proposed `async/await`, it is realized similarly like below.<br>
><br>
> ```<br>
> func fooAsync() async -> Void { ... }<br>
><br>
> fooAsync() // compilation error<br>
><br>
> await fooAsync()<br>
> // handles a completion event here<br>
> ```<br>
><br>
> However, if async void functions work like `beginAsync`, we can easily<br>
> forget it and it can cause unexpected behaviors.<br>
><br>
> ```<br>
> func fooAsync() async -> Void { ... }<br>
><br>
> fooAsync() // OK<br>
> // hard to know this line is executed asynchronously<br>
> ```<br>
><br>
> Readability also suffers seriously. If we don't know `bar` in the<br>
> following code is a async function, it is impossible to expect lines<br>
> after `baz()` are executed asynchronously.<br>
><br>
> ```<br>
> foo()<br>
> bar()<br>
> baz()<br>
> qux()<br>
> ```<br>
><br>
><br>
>>>> It’s weird to me that we would allow you to have async void closures but not async void functions<br>
>>><br>
>>> I am not sure what you mean. "async void closures" and "async void<br>
>>> functions" have a same type. Following two are almost same.<br>
>>><br>
>>> ```<br>
>>> func foo() async -> Void { ... }<br>
>>> let foo: () async -> Void = { ... }<br>
>>> ```<br>
>><br>
>> What started this thread is my suggestion that you should be able to write<br>
>> an async void function. The current proposal doesn’t allow that. That’s why<br>
>> you have to use beginAsync.<br>
>><br>
>> I don’t think that makes sense. It sounds like you also think that would be strange,<br>
>> hence your assumption that you could.<br>
><br>
> By the reasons I wrote above, we need `await` even for async void<br>
> functions for checks by compilers. Then it is required to provide a<br>
> way to write entry points of async functions. That is `beginAsync`.<br>
><br>
> --<br>
> Yuta<br>
> ______________________________<wbr>_________________<br>
> swift-evolution mailing list<br>
> <a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br>
______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br>
</div></div></blockquote></div><br></div></div></div>