The async let bindings are quite handy when you have one or two, but it is not possible to have an array of them.
I wish I could to this:
let fv: [() async -> Int] = [f, g, h]
let uv: [async Int] = [] // <--- not possible
for f in fv {
async let u = f ()
uv.append (u)
}
for u in uv {
await print (u)
}
There is a workaround, but it involves explicitly spawning tasks.
let fv: [() async -> Int] = [f, g, h]
var tv: [Task <Int, Never>] = []
for f in fv {
let t = Task {
await f ()
}
tv.append (t)
}
for t in tv {
await print (t.value)
}
In theory it would be possible I suppose but the resulting array would have to be nonescapable and it might have surprising semantics since removing an element form such array cannot remove the value from the scope — we still MUST await on it. So it could be a bit weird to use in practice… implementation might be tricky but doable.
So the question is if this is solving enough problems to warrant the complexity?
Right now I think we have bigger fish to fry, in making task groups easier to use etc. but maybe someday
Isn’t this just a task group? (Potentially with some sort of wrapper that buffers values so that they come back in order)
let fv: [() async -> Int] = [f, g, h]
await withTaskGroup(of: Int.self) { group in
for f in fv {
group.addTask { await f() }
}
for u in group {
await print (u)
}
}
Not an answer to your question (whether it will become a language feature) but the pattern potentially can become a part of the standard library. I have a utility struct called Zip in my library that serves this purpose in case of homogenous actions, and a family of functions zip(...) for non-homogenous ones, see AsyncMux/AsyncMux/Sources/Zip.swift at main · crontab/AsyncMux · GitHub