How to write f <T> (_ u: @escaping () async throws -> T ...)

To implement @ktoso's suggestion, I wrote:

func first <Success: Sendable> (
    _ wv: @escaping () async throws -> Success ...

) async throws -> Success {
    try await withThrowingTaskGroup (of: Success.self) { group in
        for w in wv {
            group.addTask { try await w() }
        }

        guard let value = try await group.next() else { fatalError ("unreachable") }
        group.cancelAll()
        return value
    }
}

But I am getting this error: @escaping attribute may only be used in function parameter position.

What is the correct way to write @escaping in that position?

That's just

func first <Success: Sendable> (
    _ wv: () async throws -> Success ...

) async throws -> Success { escape = wv[0] } 

right?

This is happening because that variadic syntax implicitly forms a parameter of type [() async throws -> Success], and, since non-escapable types are not yet officially part of the language, function parameters anywhere except at the top-level parameter/variable position are implicitly @escaping. This includes optionals and arrays.

1 Like

Thank you.

This compiles, and seems to work as expected.

func first <Success: Sendable> (
    _ wv: /* @escaping */ () async throws -> Success ...
) async throws -> Success {
    try await withThrowingTaskGroup (of: Success.self) { group in
        for w in wv {
            group.addTask { try await w() }
        }

        guard let value = try await group.next() else { fatalError ("unreachable") }
        group.cancelAll()
        return value
    }
}
Example Use
@main
enum Driver {
    static func main () async {
        var vv = [Int] ()
        let clock = ContinuousClock()

        for _ in 0..<16 {
            let elapsed = await clock.measure {
                let v = await work ()
                vv.append (v)
            }
            print ("\t-->", elapsed)
        }
        
        vv = vv.compactMap {$0 > 0 ? $0 : nil}
        print (vv)
    }
}

func work () async ->Int {
    do {
        let u = try await first_to_complete (
            { try await task (load: 3, value: 3) },
            { try await task (load: 6, value: 60) },
            { try await task (load: 6, value: 61) },
            { try await timeout (after: 7, value: -7) },
            { try await timeout (after: 3, value: -3) }
        )
        
        print (u)
        return u
    }
    catch {
        print (error)
        return 0
    }
}


func first_to_complete <Success: Sendable> (
    _ wv: /* @escaping */ () async throws -> Success ...
) async throws -> Success  {
    try await withThrowingTaskGroup (of: Success.self) { group in
        for w in wv {
            group.addTask { try await w()}
        }

        guard let value = try await group.next() else { fatalError ("unreachable") }
        group.cancelAll()
        return value
    }
}


func task (load n: Int, value: Int) async throws -> Int {
    var n = n
    while n > 0 {
        try await Task.sleep (until: .now + .seconds (1.0))
        n -= 1
    }
    return value
}

struct TimeoutError: Error {}

func timeout (after seconds: TimeInterval, value: Int) async throws -> Int {
    try await Task.sleep (until: .now + .seconds (seconds))
    #if false
    throw TimeoutError ()
    #else
    return value
    #endif
}