David Kubecka
04/10/2025, 2:43 PMclass MyClass(val scope: CoroutineScope) {
val p1 = lazy { scope.async { someExpensiveComputation() } }
val p2 = lazy { scope.async { anotherExpensiveComputation() } }
val p3 = lazy { useBothProperties(p1.await(), p2.await()) }
val p4 = lazy { useSingleProperty(p1.await()) }
}
fun main() {
runBlocking {
val myClass = MyClass(this)
myClass.p3 + myClass.p4
}
}
How can I achieve this with coroutines?
Or is there perhaps another way how to achieve my main goal (first sentence)?Sam
04/10/2025, 3:06 PMscope.async
to the provider function for p3 and p4 as well (and then call await() when accessing them)David Kubecka
04/10/2025, 3:10 PMsindrenm
04/10/2025, 3:17 PMawait
is a suspend function, you'll need to be in a coroutine context to call them. Also, when you use these in main, do you expect the method to suspend while the values are computed in the expensive operations? If so, you'll need to be in a coroutine context there, too, right? It looks to me like you'll need (want) p3 and p4 to be `Deferred`s, just like p1 and p2.sindrenm
04/10/2025, 3:18 PMscope.launch
.)David Kubecka
04/10/2025, 3:21 PMmain
function so that it's hopefully clearer what I actually want to achieve.David Kubecka
04/10/2025, 3:22 PMsindrenm
04/10/2025, 3:24 PMclass MyClass(val scope: CoroutineScope) {
val p1 = lazy { scope.async { someExpensiveComputation() } }
val p2 = lazy { scope.async { anotherExpensiveComputation() } }
val p3 = lazy { scope.async { useBothProperties(p1.await(), p2.await()) } }
val p4 = lazy { scope.async { useSingleProperty(p1.await()) } }
}
fun main() {
runBlocking {
val myClass = MyClass(this)
myClass.p3.await() + myClass.p4.await()
}
}
sindrenm
04/10/2025, 3:24 PMp3
and p4
to run in parallel?Sam
04/10/2025, 3:25 PMDavid Kubecka
04/10/2025, 3:26 PMOh, sorry, no, you also wantNo, that's not required.andp3
to run in parallel?p4
David Kubecka
04/10/2025, 3:28 PMsindrenm
04/10/2025, 3:30 PMawait
, essentially. You can also get away with passing `Deferred`s down to useBothProperties
and useSingleProperty
, but that's probably not what you want, either.David Kubecka
04/10/2025, 3:33 PMYou need it to be able toI understand that and I also understand that I need a coroutine scope for that. It just seems a little strange that once I have that scope, I can only await p1 and p2 by wrapping this with anotherawait
async->await
🙂sindrenm
04/10/2025, 3:35 PMsindrenm
04/10/2025, 3:38 PMmap
or anything on Deferred
. 😅David Kubecka
04/10/2025, 3:38 PMclass MyClass(val scope: CoroutineScope) {
val p1 = lazy { scope.async { someExpensiveComputation() } }
val p2 = lazy { scope.async { anotherExpensiveComputation() } }
val p3 = lazy {
scope.async {
useBothProperties(p1.await(), p2.await())
}.await()
}
val p4 = lazy {
scope.async {
useSingleProperty(p1.await())
}.await()
}
}
I'm just thinking that those `scope.async`s in p3 and p4 are strange. That's all.sindrenm
04/10/2025, 3:40 PMawait
outside of a coroutine context (outside of scope.async {}
).David Kubecka
04/10/2025, 3:42 PMDavid Kubecka
04/10/2025, 3:44 PMsindrenm
04/10/2025, 3:46 PMp3
and p4
to be properties, or can they be functions p3()
and p4()
?sindrenm
04/10/2025, 3:47 PMsuspend fun p3() = useBothProperties(p1.await(), p2.await())
suspend fun p4() = useSingleProperty(p1.await())
sindrenm
04/10/2025, 3:47 PMp3
and p4
, so you'd need to handle that manually.David Kubecka
04/10/2025, 3:47 PMsindrenm
04/10/2025, 3:49 PMDaniel Pitts
04/10/2025, 8:03 PMCLOVIS
04/11/2025, 7:13 AMby lazy {}
, you can:
val p1 = scope.async(start = CoroutineStart.LAZY) { someExpensiveComputation() }
Sam
04/11/2025, 7:15 AMCLOVIS
04/11/2025, 7:17 AMp3
/`p4` are accessed when p1
/`p2` have not finished computing yet?David Kubecka
04/11/2025, 11:27 AMscope
val (from the top-level runBlocking
) and want to evaluate myClass.p3
with this scope. Obviously, I cannot use async/await because for await
I would need another scope...David Kubecka
04/11/2025, 11:32 AMDavid Kubecka
04/11/2025, 11:37 AMwithScope(scope) {
myClass.p3.await()
}
(assuming p3
is Deferred
)CLOVIS
04/11/2025, 12:16 PMp3
/`p4` are accessed when p1
/`p2` have not finished computing yet?David Kubecka
04/11/2025, 12:28 PMp3
/`p4` should wait for p1
/`p2` to finish. AFAIK that's written in my original example, e.g.
val p3 = lazy { useBothProperties(p1.await(), p2.await()) }
CLOVIS
04/11/2025, 12:31 PMp3
/`p4` to suspend
, you don't a choice except having them be Deferred
or suspend fun
, yeahDavid Kubecka
04/11/2025, 12:34 PMDeferred
but how do I await
on it (e.g. in main
) if I only have the scope
?CLOVIS
04/11/2025, 12:38 PMyourClass.p3.await()
?David Kubecka
04/11/2025, 12:51 PMfun main() {
val myClass = runBlocking {
MyClass(this)
}
p3.await() // how to use myClass.scope here?
}
The context is GraphQL data fetchers where I set up the MyClass
context in the entry method and then want to access the computed properties in some data fetcher, i.e. outside of the runBlocking
scope.Daniel Pitts
04/11/2025, 8:01 PMDaniel Pitts
04/11/2025, 8:09 PMpackage com.stochastictinkr
import kotlinx.coroutines.*
class MyClass(scope: CoroutineScope) {
val p1 by lazy {
scope.async {
println("start fetching p1")
delay(1000)
println("p1 done")
3
}
}
val p2 by lazy {
scope.async {
println("start fetching p2")
delay(1000)
println("p2 done")
2
}
}
val p3 by lazy {
// Ensure that p1 and p2 are started before we await either of them.
val p1 = this.p1
val p2 = this.p2
runBlocking {
p1.await() + p2.await()
}
}
val p4 by lazy {
runBlocking {
p1.await() * 3
}
}
}
fun main() {
val obj = MyClass(CoroutineScope(Dispatchers.Default))
println("p3: ${obj.p3}")
println("p4: ${obj.p4}")
}
The output is:
start fetching p1
start fetching p2
p1 done
p2 done
p3: 5
p4: 9
CLOVIS
04/12/2025, 9:38 PMrunBlocking
in this situation, that undermines the entire point of coroutines (not cancellable, not compile-time declared, no structured concurrency)Daniel Pitts
04/12/2025, 11:56 PMCLOVIS
04/14/2025, 7:23 AMsuspend
in other places in your application, meaning these properties will likely be accessed from deeper in the call stack than a suspend
function, and using runBlocking
there will break most guarantees offered by coroutinesDavid Kubecka
04/14/2025, 10:43 AM