Is it correct to rely on thread_local! behavior of defining a const value instead of static?

Or is it considered a implementation detail and therefore must not be relied upon?

There are some patterns that are currently possible to achieve with the generated const LocalKey value that would not be possible if the macro generated a static LocalKey value. Both static and const variables can refer to other const values but a const variable cannot refer to a static variable. As an example, referencing thread local keys inside const functions and blocks is allowed, but that would not be the case if they were defined as static.

I am interested in implementing a type (MyWrapper) that would "wrap" a LocalKey type. I want to be able to create const values for this type. The type could either own a LocalKey, and then I would use the thread_local! value (relies on said behavior) to create it, or the type could just hold a key reference (&'static LocalKey), which would still work even if at some point (if ever) the macro were to generate static values. The second option comes with the downside that my implementation would need to resolve &'static MyWrapper and then &'static LocalKey whenever operating the key over MyWrapper. But I guess the compiler may be able to optimize the double indirection in this case.

I appreciate your insights.

Rust std almost always takes a strict stance on source compatibility, only really making exceptions for unavoidable name resolution or type inference breakage and soundness fixes. It should be fine to rely on thread_local! items being const values.

W.r.t. indirection, the implementation of LocalKey actually also contains more indirection than you might think strictly necessary, and contains an interesting comment about it:

Although this is an extra layer of indirection, it should in theory be trivially devirtualizable by LLVM because the value of inner never changes and the constant should be readonly within a crate. This mainly only runs into problems when TLS statics are exported across crates.

The fact that the LocalKey is a const without a meaningful address helps with this transparency to the optimizer. I would probably suggest avoiding keeping long-lived &LocalKey if you can do so.

1 Like

I see. I know Rust takes a strict approach for breaking changes, but since this is fully behind a macro and the documentation calls them static declarations, I couldn't quite tell if I was overstepping a public guarantee.

Yeah I'm looking at the source now, It is a bit more complicated that I would've imagined but I don't think that would be a problem for my use case.

I intent to use them for short periods, just to run some closures against the key, very similar to LocalKey's with_... functions.
Thank you!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.