is there a generic way of handling combinations of async and throws in swift

Viewed 81

I am finding very little documentation on swift concurrency - so I'm finding I have to build most of my own async tools, even though they might already exist somewhere.

However - in most cases I need to make four copies of essentially the same function. For instance - suppose I want an actual proper async "run function after a delay of this long" - I end up with

    //
    // do this after this amount of time
    //
    public static func after<T>( ms : Int, function : () -> T) async -> T
    {
        await delay(ms: ms)
        return function()
    }

    //
    // do this after this amount of time
    //
    public static func after<T>( ms : Int, function : () throws -> T) async throws -> T
    {
        await delay(ms: ms)
        return try function()
    }

    //
    // do this after this amount of time
    //
    public static func after<T>( ms : Int, function : () async -> T) async -> T
    {
        await delay(ms: ms)
        return await function()
    }
    
    //
    // do this after this amount of time
    //
    public static func after<T>( ms : Int, function : () async throws -> T) async throws -> T
    {
        await delay(ms: ms)
        return try await function()
    }

so I'm wondering if there's any way of saying that in one function instead - basically saying "and it should work with a function with any combination of async/throw"

1 Answers

You can simply use this syntax for the most generic solution:

func after<T>(ms: Int, function: () async throws -> T) async rethrows -> T {
    delay(ms: ms)
    return try await function()
}

rethrows: Only throw when the inner function throws

async: You can also pass a synchronous function to the async part; that doesn't matter

Examples:

// No error thrown (no need for try); function is not async
let a = await after(ms: 10) { return 1 }

// No error thrown; function is async
let b = await after(ms: 10) { return await after(ms: 20) { return 2 } }

// Error thrown (try needed); function is not async
let c = try await after(ms: 10) { throw NSError() }

// Error thrown; function is async
let d = try await after(ms: 10) { return try await after(ms: 20) { throw NSError() } }
Related