6

In Swift 5.5:

Following Swift Code will get compiler error: "async call in a function that does not support concurrency".

// Swift
func hi() async {
    print("hi")
}

func callAsyncHi() {
    hi()
}

In Javascript, await is only valid in async function, but calling an async func from a normal func is valid. So following Javascript Code prints "hi" asynchronously.

// Javascript
async function hi() {
    console.log("hi")
}

function callAsyncHi() {
    hi()
}

callAsyncHi()

I also found an async func cannot be called without await or async let. Why Swift is designed in this way?

2
  • Use await hi() to invoke that async function. You can find reasons on why you write await when invoking async function here: docs.swift.org/swift-book/LanguageGuide/Concurrency.html Commented Mar 18, 2022 at 4:23
  • because default swift behavior is not async, async/await is new and it suspend the following codes. so when to call async func in non-async function, you need put it in a Task advancedswift.com/async-await/… Commented Mar 18, 2022 at 4:26

2 Answers 2

13

You can invoke async function from normal function by wrapping the asynchronous call inside a task:

func hi() async {
    print("hi")
}

func callAsyncHi() {
    let task = Task {
        await hi()
    }
}

This is similar to how you can invoke async methods in java script from synchrnous context, key difference being in Swift you have to explicitly specify it and inside Task you can invoke more than one async methods.

There are certain reasons behind a design like this. Key reason being in Swift all async methods are associated with tasks and support cooperative cancellation.

Swift concurrency uses a cooperative cancellation model. Each task checks whether it has been canceled at the appropriate points in its execution, and responds to cancellation in whatever way is appropriate.

By requiring async keyword Swift keeps track of the dependency chain of async calls and propagates cancellation event when it occurs (While as far as I know promises in JS doesn't support cancellation of promises). In the above code, you can invoke cancellation on task variable by keeping track of it.

Now the second reason, more important in my opinion, is by requiring explicit invocation this makes it easier to review code as I have to check if cancellation for such invocations are properly handled while in case of JS it is harder to pinpoint such misuse.

Sign up to request clarification or add additional context in comments.

Comments

-4
  • An async function from Javascript returns a Promise.
  • An async function from C# returns a Task.

We pass Promises/Tasks around freely and do many things.

But an async function from Swift returns ???.

??? is hidden. I cannot even print its type.

// swift compiler error: Expression is 'async' but is not marked with 'await'
func callAsyncHi() {
  Task {
    async let tmp = hi()
    print(Mirror(reflecting: tmp).subjectType)
    await tmp
  }
}

I guess there is no ???. So we have to use async func with await.

2 Comments

After reading forums.swift.org/t/se-0296-async-await/42605 . I found my guess is correct. There is no Future/Promise type in async/await for better compiler optimization. But I do need them... I will stick to Google/Promises. I don't like async keyword to pollute other func.
that's a very bad idea. In swift you can write two functions, the signature difference only being the asynchronous, and then consumers can use EITHER of the two functions you have written !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.