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> 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

Reply via email to