ScopedValue structured forking/forwarding API
Nikita Bobko
nikita.bobko at jetbrains.com
Fri Jul 11 19:05:31 UTC 2025
Andrew Haley wrote:
> handshake to make sure that
> every Snapshot has been join()ed at the end of Carrier.run(). I guess
> that would work if we could figure out a sound way to do it
I'm curious as to what makes you doubt that it can be done in a sound
way. StructuredTaskScope already does that, doesn't it?
Andrew Haley wrote:
> Given that a StructuredTaskScope can work with any ThreadFactory, why do
> you need to replicate its working? What do you need to do differently?
Great question. I'm trying to make kotlinx.coroutines seamlessly work
together with ScopedValues. Similar to how StructuredTaskScope endorses
structural concurrency, kotlinx.coroutines endorses structural
concurrency as well.
But StructuredTaskScope and kotlinx.coroutines use threads in a
different way. For StructuredTaskScope, thread is *the unit* of
structural work. For kotlinx.coroutines, thread is just a resource (like
memory) that we use to run coroutines on.
Coroutine is *the unit* of structural work in the kotlinx.coroutine
world. Coroutines are lightweight threads, and they are implemented via
async/await code-coloring and Continuation Passing Style transformation
(CPS-transformation) made by the Kotlin compiler.
kotlinx.coroutines framework allows to choose which threads users want
to run their Coroutines on. For example, UI main thread is an important
case where users care on which thread Coroutines run on.
Unlike in StructuredTaskScope, threads that we run Coroutines on could
had existed long before ScopedValue.Carrier.run() was called.
We don't use threads structurally. But the jobs (coroutines) that we
submit on those threads are structural. And the child coroutines are the
place where I want to forward ScopedValues to. Not child threads, but
child coroutines. Unfortunately for us, StructuredTaskScope assumes that
*the unit* of structural work is thread.
Andrew Haley wrote:
> I'm still curious about this:
>
> > However, it is straightforward to create a scoped value class of your
> > own that has any properties you wish, including different inheritance
> > rules. Given a ScopedValue.Carrier that binds some values, start your
> > thread with aCarrier.run(task). Would this work for you?
My task is to seamlessly integrate kotlinx.coroutines and ScopedValues.
Unfortunately, your suggestion doesn't work for us, because we would
need to ask users to manually pass ScopedValue.Carrier bindings to
kotlinx.coroutines.
More information about the loom-dev
mailing list