ibex10
August 5, 2024, 12:01pm
1
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?
ktoso
(Konrad 'ktoso' Malawski 🐟🏴☠️)
August 5, 2024, 12:05pm
2
That's just
func first <Success: Sendable> (
_ wv: () async throws -> Success ...
) async throws -> Success { escape = wv[0] }
right?
j-f1
(Jed Fox)
August 5, 2024, 2:21pm
4
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
ibex10
August 6, 2024, 12:44am
5
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
}