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. > 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 = { ... } ``` -- Yuta 2017-11-11 11:02 GMT+09:00 Adam Kemp <adam_k...@apple.com>: > I’m not sure that answered my questions. > > Can I do this? > > let asyncClosure:() async -> Void = { await doSomethingAsync() } // Can you > declare an async closure variable? > > beginAsync(asyncClosure) > > > What about this? > > let syncClosure:() -> Void = { doSomethingSync() } > > beginAsync(syncClosure) // Can a non-async closure be passed to a function > expecting a async closure? > > > And this? > > > func callSyncClosure(_ closure:() -> ()) { closure() } > > > let asyncClosure:() async -> Void = { await doSomethingAsync() } > > > callSyncClosure(asyncClosure) // Can an async closure be passed to a > function expecting a non-async closure? > > > Here are my thoughts on each of these: > > Can you declare an async closure variable? If async is part of the type then > it would be very strange not to allow this. I think the proposal implies > that you can, but only by way of an example about inferring whether a > closure is async or not. > > Can a non-async closure be passed to a function expecting a sync closure? > This seems like an obvious conversion. I feel like disallowing this would > probably make things harder, but I haven’t thought it through enough to say > exactly how. Are there reasons that this shouldn’t work, though? > > Can an async closure be passed to a function expecting a sync closure? This > may be controversial, but I think this should be allowed too. I think a > caller that expects a void-returning synchronous function should be able to > call an async function and treat it as a call-and-forget. > > It’s weird to me that we would allow you to have async void closures but not > async void functions, but in order to support beginAsync we have to have > async void closures. So if we can make that work then why couldn’t we just > make async void functions work and dispense with beginAsync entirely? > > On Nov 10, 2017, at 1:38 AM, Yuta Koshizawa via swift-evolution > <swift-evolution@swift.org> wrote: > > I’m not sure how the proposed design handles type checking for async > closures. Is async part of the type? Can I declare a local closure variable > as async? What are the rules for conversion between async and non-async > closures? Is it a warning or error to use a closure literal without an async > keyword that is assigned to an async closure variable or passed as an async > closure argument? > > > It has been already realized for `throws`. > > ``` > // This works in Swift 4 > func foo(_ f: (Bar) throws -> Baz) > > // This can be checked in the same way > func foo(_ f: (Bar) async -> Baz) > ``` > > Proposed `async/await` in Swift are analogous to `throws/try`. So a > lot of things about `async/await` can be imagined when we think about > `throws/try`. It is also true for `(Foo) async -> Void`. We can use it > in the same way as we use `(Foo) throws -> Void`. > > `async/await` as an analogy to `throws/try` works well because both of > them can be mapped to monads. `throws` is similar to `Result` and > `async` is similar to `Promise` ( `Future` ). > > ``` > // `a` and `b` are similar > func a() throws -> Int > func b() -> Result<Int> > > // `c` and `d` are similar > func c() async -> Int > func d() -> Promise<Int> > > // `a` : `b` == `c` : `d` > // `a` : `c` == `b` : `d` > ``` > > `try` and `await` are also similar to `flatMap`. ( I think most > popular `Promise` is one in JavaScript. Although it does not have > `flatMap`, its `then` method can be considered as `flatMap`. ) > > ``` > let x = try a() > // uses `x` here > > b().flatMap { x in > // uses `x` here > } > > let y = await c() > // uses `y` here > > d().flatMap { y in > // uses `y` here > } > ``` > > So `throws` : `try` : `Result` == `async` : `await` : `Promise` and > `throws` : `async` == `try` : `await` == `Result` : `Promise`. I think > those relations are beautiful and proposed `async/await` fits well to > Swift because we have already had `throws/try`. > > -- > Yuta > > > 2017-11-10 6:45 GMT+09:00 Adam Kemp via swift-evolution > <swift-evolution@swift.org>: > > > On Nov 9, 2017, at 11:02 AM, Wallacy <walla...@gmail.com> wrote: > > So for me, this: > > func OnButtonClicked(_ sender:AnyObject) { > > let button = sender as! UIButton > button.isEnabled = false > beginAsync { > await DoSomethingAsync() > button.isEnabled = true > } > } > > > Does not make any sense... Because await will not block the thread we can > assume (like the exemple on proposal) that compiler will actually do the > same what we will do using GDC and pick everyone to until the context ends > and encapsulate as completion handle to the away call. > > > I don’t understand what you’re saying here. In terms of GCD the above code > is basically equivalent to this: > > func buttonClicked(_ sender:AnyObject) { > let button = sender as! UIButton > button.isEnabled = false > doSomethingAsync { // completion callback, assume it’s on the main queue > button.isEnabled = true > } > } > > > And this one: > > @IBAction func buttonDidClick(sender:AnyObject) { > beginAsync { > let image = await processImageData() > // Do the update on the main thread/queue since it owns imageView. > mainQ.async { > imageView.image = image > } > } > } > > > > Does not make any sense too. > > The only way to await to do not block the thread is make a early return like > beginAsync and encapsulate as completion handle the rest of the code. > > > This is why “await” can only be used in a function that is marked as > “async”. The “async” keyword tells the compiler that this function will be > broken up into parts, and its return value will be produced asynchronously. > > One thing that might be confusing is that in the examples using “beginAsync” > the trailing closure is the async function. That’s not obvious because > there’s no “async” keyword, but it’s there in the signature of the closure > argument: > > func beginAsync(_ body: () async throws -> Void) rethrows -> Void > > > I’m not sure how the proposed design handles type checking for async > closures. Is async part of the type? Can I declare a local closure variable > as async? What are the rules for conversion between async and non-async > closures? Is it a warning or error to use a closure literal without an async > keyword that is assigned to an async closure variable or passed as an async > closure argument? > > C# dodges all of these issues because async isn't part of the type system. > Closures that don’t return anything can be declared async just like void > functions, and code that uses void-returning closures doesn’t need to care > whether the implementation is async or not. > > > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution > > _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution