Skip to content
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

Extension functions for bulk collection operations #2357

Open
Minirogue opened this issue Nov 2, 2020 · 3 comments
Open

Extension functions for bulk collection operations #2357

Minirogue opened this issue Nov 2, 2020 · 3 comments

Comments

@Minirogue
Copy link

I'm guessing the answer might be "if you need it, then you can write your own extension functions", but I was wondering if it might be worth adding suspend extension functions for Collection. For context, I've found myself recently using

val taskResults = someList.map {
    async {
        performSomeTask()
    }
}.awaitAll()

One could also reasonably use launch (and joinAll() if necessary) if the results of performSomeTask aren't needed. The general use case is "I want to perform a task on a collection of items asynchronously". I wrote my own extension function and I'm wondering if it is worth something like this being in the library itself:

suspend inline fun <T, R> Collection<T>.asyncMap(crossinline transform: suspend (T) -> R): List<Deferred<R>> =
    coroutineScope { map { async { transform(it) } } }

Naturally, there is some cleanup and due diligence needed: it should probably be on Iterable instead of Collection, it should probably take a CoroutineContext, maybe there should be a suspendMap or awaitMap that also calls awaitAll(), etc. Also, there's probably some other functions in addition to map that could use this treatment (zip?) if it is determined to be something worth adding to the library.

Everything I look at that seems related to this points to #172, which appears to potentially be at a dead-end, since actor has been marked with @ObsoleteCoroutinesApi and there has been no activity there since February 2019 (with the last linked issue in October 2019). Also, while digging to see if this has been brought up, it looks like I'm certainly not the first to come up with this solution: #1022. Also, that issue raises another reason for this to not be in the library: it could saturate the dispatcher if we're not careful.

Even so, I think it's a common enough use-case that it's worth bringing up. It might seem small, but it saves an indentation and I don't think it's any more trivial than awaitAll() or joinAll(), which have already initiated the idea of coroutine collection extension functions.

@fvasco
Copy link
Contributor

fvasco commented Nov 2, 2020

Are you considered #1147?

@Minirogue
Copy link
Author

Hmm, everything I'm seeing seems to want to use Flow. For what I want to do that would require doing

someList.asFlow().concurrentMap() { performSomeTask() }.toList()

It could be a solution for an implementation of what I'm looking for, but I think a lot of people learning coroutines from scratch will be more prone to using launch and async type methods. For "simple" batch operations, Flow may feel like a bit much for a beginner.

@elizarov
Copy link
Contributor

elizarov commented Nov 5, 2020

We try to layer our design so that things like launch and async provide low-level building blocks, while Flow provides high-level "declarative" operations which let you declare "what do you want to get" and let the infrastructure of the corresponding coroutines be set up for you. It does not preclude the extensions for doing bulk concurrent operations to appear directly on the collection types in the future, but the design of the corresponding operations for Flow will come first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants