swiftasync-awaitclosuresswift-concurrency

Result return types vs async and await


When a function returns a success and error Result, is it necessary that the function be marked as async with await?

For example…

func asyncStoreData(_ image: UIImage, dateTaken: Date) async -> Result<String, Error> {
    // Implementation of the function body...
}

Solution

  • No, just because a function returns a Result, that does not mean that you have to decorate the function with async. One would only mark a function as being async if the code inside the function performs an await. Without seeing your implementation, one might reasonably infer that your implementation does await something, and thus it would be correct to mark this as an async function, but it is impossible to confirm this without more information about the implementation.

    In short, we only use async functions if those functions await something. The return type of the function is not relevant.


    As an aside, in your original question, you said “When a function return completion block with success and error result…”. There is no completion block here. Do not conflate Result return types and “completion blocks”. They are two different things. Sure, we tend to use Result types with legacy completion-handler code, but the converse is not true: The presence of Result does not mean that you are using completion handler closures. In your example, there is no completion closure.


    FWIW, when adopting Swift concurrency, not only would we retire completion closures, but frequently we cease using Result return types, too. Typically, it would be:

    func asyncStoreData(_ image: UIImage, dateTaken: Date) async throws -> String {
        // Implementation of the function body...
    }
    

    One of the key features of Swift concurrency is we can retire the syntactic noise of both completion blocks and Result types. The Result type was a very convenient way of returning a success/failure result back in the day of completion handler closures. But, async-await often renders the old Result type moot.

    That having been said, there edge-cases where we still use Result return types in Swift concurrency. It is less common, but we might do so in some isolated cases.

    So, if you are reviewing a Swift concurrency codebase that has a method that returns a Result type, that does not necessarily mean that there is a mistake. But, you might want to review the code and ask yourself whether this is appropriate. Namely, the question is whether there is some utility in encumbering the code with the syntactic noise of Result types, and whether that is really appropriate. (But that is a separate question, out of scope here.)