ScopedValue performance declines as number of dynamic bindings increases

Robert Engels robaho at me.com
Tue Jun 24 15:16:47 UTC 2025


The Java code has no valid benchmarking that i can see ???

> On Jun 24, 2025, at 10:12 AM, Johan Sjolen <johan.sjolen at oracle.com> wrote:
> 
> Hi,
> 
> I've been working on implementing a feature and the ScopedValue preview feature was an excellent fit to a particular design problem I faced.
> Reading the source code, I noticed that it seems as though the linked list of value bindings are shared across all ScopedValue instances. This was a bit surprising to me, as this means that the performance of accessing
> a ScopedValue binding declines linearly with the number of bindings before it on the stack.
> 
> The ScopedValue feature has a long heritage, with historical roots in Lisp and Scheme. The most similar implementation that I know of is that found in Racket, where they are called Parameters[0]. Parameters are also inherited by child threads, and are accessed per thread. Guile, a different Scheme, calls ScopedValue thread-local fluids[1].
> 
> Okay, so multiple languages have these things, do they have the same performance implications? The answer seems to be no.
> I wrote a number of benchmarks, for Java, Racket and Guile. The Racket benchmark shows no discernible difference in performance, and neither does Guile Scheme, however the Java benchmarks show a very large difference in runtime. It makes sense that the Scheme languages optimize for this case, as they use parameters a lot. For example, with-output-to-file rebinds the current-output-port in order redirect the output to a file. If accessing this variable required traversing a linked list each time, then the performance of the system as a whole would suffer. These languages show how ScopedValues have come to be used by languages which have had these features for a long time. Namely, they provide a reasonable default (current-output-port pointing to stdout), whilst allowing the user to manipulate the parameters in order to change behavior when needed.
> 
> I'm wondering about the reasoning and trade-offs here, what do we get with our implementation that the Schemers do not? Maybe we should consider changing our implementation?
> 
> Cheers,
> Johan
> 
> ScopedTest.java:
> https://gist.github.com/jdksjolen/19133aa25f1008eee34bab07d4c94eab
> ScopedTest2.java:
> https://gist.github.com/jdksjolen/2b689d91873b411bdcbfc790a7238f5a
> 
> Racket benchmark code:
> https://gist.github.com/jdksjolen/9598ec7a8c4a925b2913a9062d4d9917
> Guile benchmark code:
> https://gist.github.com/jdksjolen/cfbf22976f17bec2d9b08b1e6f976bad
> 
> [0] https://docs.racket-lang.org/reference/parameters.html
> [1] https://www.gnu.org/software/guile/manual/html_node/Thread-Local-Variables.html


More information about the loom-dev mailing list