ScopedValue.runWhere not returning scope

Andrew Haley aph-open at littlepinkcloud.com
Fri Jun 7 09:17:26 UTC 2024


Hi,

On 6/6/24 21:53, Marcin Grzejszczak wrote:

 >  > If you consider an execution of a program as a downwards-growing
 >  > stack, a scoped value is bound to some value at one point in the
 >  > stack, and the bound value is visible to all frames below that
 >  > point. That is all: there's no need to consider scopes opening
 >  > and closing.
 >
 > In theory that's true. But if we take into consideration frameworks
 > like Brave [1], Micrometer [2], OpenTelemetry [3] , Apache Camel
 > [4], Apache Skywalking [5] etc. (so those that work with distributed
 > tracing) that theoretical viewpoint does not hold. It would be a
 > gigantic shame if they would need to always rely on ThreadLocals
 > instead of being able to use the ScopedValues mechanism.

I don't understand this. Why would it be a shame? The differences
between scoped values and thread-local variables are that scoped
values are one-way from caller to callee and strictly nested. The use
pattern that you are presenting loses those properties that make
scoped values distinct. If you need an unstructured context object
you've got a solution already, thread-local variables. Why do you want
to use scoped values?

 >  > It's true that this decision makes scoped values less versatile
 >  > than thread-local variables, but on the other hand the hard
 >  > guarantees it provides make programs easier to reason about. On
 >  > balance, we consider the latter more important than the former.
 >
 > I completely agree with that however for library instrumentors this
 > separation is extremely important. Also that would cancel out all
 > libraries that want to use scoped values and work in an SPI model
 > where users can add functionalities in an isolated fashion (separate
 > before and after logic).

Can you explain that a little more? Why can't isolated functionality
be added without separate before and after logic?

 > It would require all of the frameworks that I mentioned to
 > completely rewrite their internals so that the user's code execution
 > would be wrapped in a e.g. `ScopedValue.runWhere`.

That's true.

 >  > We did consider (and even implement) an API with open() and
 >  > close() methods, but we discarded it in order to make the use you
 >  > describe impossible
 >
 > I understand that with great power comes great responsibility and
 > you want to guard users from cases like "opening and not closing".

Exactly, and it makes a difference to code quality when we know that a
scoped value cannot change during the lifetime of a method, even if
other methods are called or if a (virtual) thread is suspended and
resumed. A scoped value is effectively constant for the lifetime of a
method.

Out of curiosity, what do you think should happen, specification wise,
if scoped value bindings are closed out of order?

 > I fully understand that because I've been working in the domain of
 > distributed tracing for a decade now and I've seen that particular
 > scenario happen every now and then. It's not a common situation
 > though. Since you've already implemented it once then you did see
 > reasons for doing that. Is there a chance to come back to that
 > discussion? What would need to happen to reopen that conversation
 > once again?

Given that it would lose the most fundamental distinction between
thread-local variables and scoped values, I'd say that it'd take some
kind of miracle.

The point of any structured programming construct is to restrict
programmers. Any program may be written with conditional jumps, but we
don't do that any more because it makes programs hard to reason about.
Anything that you can do with a scoped value you can also do with a
thread-local variable, albeit a little less efficiently. The added
efficiency of scoped values is a direct result of the restrictions
that we place on the way they may be used.

-- 
Andrew Haley  (he/him)
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
https://keybase.io/andrewhaley
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671



More information about the loom-dev mailing list