<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">I posted a minimalist “tracing library” using ScopedValue here <a href="https://github.com/robaho/scope_trace" class="">https://github.com/robaho/scope_trace</a><div class=""><br class=""></div><div class="">I think it is a fairly trivial change for tracing libraries to support ScopeValue instead of ThreadLocal if they wished to.</div><div class=""><div class=""> <br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Jun 11, 2024, at 7:35 AM, Andrew Haley <<a href="mailto:aph-open@littlepinkcloud.com" class="">aph-open@littlepinkcloud.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">On 6/11/24 11:32, Marcin Grzejszczak wrote:<br class=""><br class="">>> So why not produce an example of how it would be used? As far as I can<br class="">>> see, your proposal fails to ensure the property in the case I posted/<br class="">><br class="">> I've created samples at the very beginning with the before and after<br class="">> interceptor. I obviously know that I could rewrite the interceptor<br class="">> to become an around one but my point is that it's not an ideal<br class="">> solution to require instrumentors to rewrite everything. Also I<br class="">> still see this whole discussion as having two ways of doing the same<br class="">> thing. Current approach:<br class="">><br class="">> ScopedValue.runWhere(scopedValue, someValue, () -> {<br class="">> codeToRun();<br class="">> });<br class="">><br class="">> Proposed approach:<br class="">><br class="">> try(Scope scope = ScopedValue.openScope(scopedValue, someValue)) {<br class="">> codeToRun();<br class=""><br class="">This API fails the test I provided:<br class=""><br class=""> final ScopedValue aScopedValue = ...;<br class=""> final var x = aScopedValue.get();<br class=""> ScopedValue.openScope(aScopedValue, someValue);<br class=""> final var y = aScopedValue.get();<br class=""><br class=""> assert(x == y); // Always succeeds<br class=""><br class="">In other words, scoped values would no longer be strictly scoped.<br class="">That's what the "scoped" means in the name "scoped values". Strict<br class="">scoping is a fundamental property.<br class=""><br class="">> }<br class="">><br class="">> I understand that in the proposed approach one can mess things up, I<br class="">> really do. But library instrumentors and tracing library creators<br class="">> would benefit from that sort of API.<br class=""><br class="">If we were planning to deprecate thread-local variables I think this<br class="">argument might have some merit. But we're not. They're not going away.<br class=""><br class="">> Also I've asked a different question... What if the users want to<br class="">> leverage the ScopedValues to get the current span information (or<br class="">> current principal from security point of view) but also they are<br class="">> using TL based libraries? How would the interop look like?<br class=""><br class="">As the JEP says, scoped values do not replace all uses of thread-local<br class="">variables. There are still some cases where thread-local variables<br class="">will be used, and this looks like one of them.<br class=""><br class="">> Let's assume that they put into the current scope a span that they<br class="">> want to have within that scope, we would need all the tracer<br class="">> libraries (and security components and others that use the same<br class="">> mechanism) to be ScopeValue aware. Would they first try to read SV<br class="">> and then if that's not there a TL?<br class=""><br class="">Yes, I think so.<br class=""><br class="">> They would need to most likely read SV and populate TL if the SV<br class="">> value is present so that other components that still rely on TL<br class="">> would work. That would have to also work the other way round, if a<br class="">> TL based library sets a value (e.g. span) then maybe the ScopedValue<br class="">> should be created with a scope for that new value?<br class=""><br class="">I'm not sure how that'd work in general, but there's nothing to stop<br class="">entry points for a library from doing so, and it might be a good idea.<br class="">Something like:<br class=""><br class=""> if (someThreadLocal.get() != NOTHING) {<br class=""> where(someScopedValue, someThreadLocal.get()).run(realEntry);<br class=""> } else {<br class=""> realEntry.run();<br class=""> }<br class=""><br class="">-- <br class="">Andrew Haley (he/him)<br class="">Java Platform Lead Engineer<br class="">Red Hat UK Ltd. <<a href="https://www.redhat.com" class="">https://www.redhat.com</a>><br class=""><a href="https://keybase.io/andrewhaley" class="">https://keybase.io/andrewhaley</a><br class="">EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671<br class=""><br class=""></div></div></blockquote></div><br class=""></div></div></body></html>