-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Propose shortcut for Iterable<Deferred<T>> → Flow<T> e.g. map { it::await.asFlow() }.merge() #2752
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Why not do this as
|
Sounds good, I don't know the merits of Another point in favor of a canonical shortcut? |
If it gets implemented, I think more idiomatic would be to call it |
I have a collection of deferreds and I need to get the first one to complete with a non-null value. Backing up, I start with a collection of objects (tax forms) which I evaluate concurrently and I need to get the first occurrence of a specified tax line. Each form returns My code looks something like the following (eliding most of it): class EvalVisitor(file: File, val scope: CoroutineScope) {
// ...
// Look up a single line number
fun FormParser.RangesContext.single(): Deferred<Any?>? {
val (line, part, form) = visit(this).single()
// ...
// First occurrence in the listed forms of the specified line number
return listOf(yourReturn, schedule1, form428).get(line, part)
}
fun Iterable<EvalVisitor?>.get(line: String, part: String? = null): Deferred<Any?> {
// Evaluate each form concurrently
val bound = mapNotNull { it?.get(line, part, this@EvalVisitor) }
// First non-null result
return scope.async { bound.map { it::await.asFlow() }.merge().filterNotNull().firstOrNull() }
}
fun get(line: String, part: String?, caller: EvalVisitor): Deferred<Any?>? {
// ...
}
} In the absence of a shortcut I use channelFlow {
for (deferred in bound) {
launch { send(deferred.await()) }
}
}
.filterNotNull()
.firstOrNull() or channelFlow {
for (deferred in bound) {
launch { deferred.await()?.let(::send) }
}
}
.firstOrNull() I propose e.g. Ultimately I start with an Keeping with flows, I could introduce them before concurrently evaluating the forms vs. after ( flowOf(yourReturn, schedule1, form428)
// Like in https://github.com/Kotlin/kotlinx.coroutines/issues/1147
.concurrent { flow -> flow.mapNotNull { it?.get(line, part, this@EvalVisitor) } }
.merge()
.filterNotNull()
.firstOrNull() vs. listOf(yourReturn, schedule1, form428)
.mapNotNull { it?.get(line, part, this@EvalVisitor) }
.race()
.filterNotNull()
.firstOrNull() |
What do you think about adding the following to the library:
Call it:
Iterable<Deferred<T>>.merge()
likeIterable<Flow<T>>.merge()
asCompleted()
like Pythonconcurrent.futures.as_completed()
race()
likePromise.race()
Currently I use
deferreds.map { it::await.asFlow() }.merge().filterNotNull().firstOrNull()
to get the first in a collection of deferreds to complete with a non-null value.The proposed shortcut isn't much shorter, but:
Iterable<Deferred<T>>
→Flow<T>
has general utilityconcurrent.futures.as_completed()
,Promise.race()
map { it::await.asFlow() }.merge()
) makes it clearer and easier to find and use?Unless there's already a better way of doing the same thing?
Previously proposed during the discussion of #171
The text was updated successfully, but these errors were encountered: