I'm running into an issue when using select, and I...
# coroutines
m
I'm running into an issue when using select, and I might just be missing something very simple. Maybe someone here can spot what I'm doing wrong? I have the following code:
Copy code
suspend fun select(contentMap: Map<Content, VideoContentItemHolder>) = coroutineScope {
    select<Content> {
        contentMap.forEach { content, itemHolder ->
            launch { itemHolder.onClick() }.onJoin {
                content
            }
        }
    }
}
VideoContentItemHolder.onClick() is a suspending function. Basically I am waiting for any of the itemHolder.onClick() to complete, and then returning the associated Content-object. I have attached the debugger to see that onClick() successfully completes for one of the itemHolders and I enter the onJoin-block, but the select clause never gets a result. So anyone waiting for the result is suspended indefinitely.
a
What do you expect as result?
forEach
returns
Unit
m
I'm expecting a result of Content. I'm trying to select a deferred value. Like here: https://kotlinlang.org/docs/reference/coroutines/select-expression.html#selecting-deferred-values
I think the select-block is expecting Unit, so the forEach should be fine as long as I return a Content-object inside the onJoin-block. But maybe I'm misunderstanding something there?
a
It is rather hard to see through it. Probably it is better to move launches from select.
m
👍 I'll try that
a
Not sure it will help. But launching coroutines in select is bad practice anyway.
m
Hmm, I just tried creating the Jobs outside of the select-block. Unfortunately didn't make any difference 😞
Seems to be my lack of understanding of Scope. My current implementation waits for all Jobs to complete, not just one of them. If I replace launch with GlobalScope.launch f.x. it works. I'll have to look more into that to figure out how I should be handling this.
a
coroutineScope
is not needed here, yet I don't understand why it behaves like this.
b
The
coroutineScope
is suspending until after all of your item holders have been clicked. If this isn't the intended behavior, cancel all of your other jobs in the onJoin:
Copy code
.onJoin {
    this@coroutineScope.cancelChildren()
    content
}
Your select clause is completing, but your
coroutineScope
won't return until all of the other launched jobs have completed. Thus preventing leaked jobs via Structured Concurrency
👍 1
m
Makes sense, thanks @bdawg.io 🙂