I’ve been recently wondering about how the idea of making TyCtxt a global would be like. Some notable benefits of using a thread local are:
- Less syntax noise. This eliminates the
tcx
parameter that is put on almost every function. - Availability of
TyCtxt
inside library trait impls. Useful cases include formatting traits (Display, Debug), serialization traits, and finally Drop.
In the following of this post, I will discuss the limitations of scoped thread local (which is already implemented as ImplicitCtxt
but rarely used), followed with a new proposal of thread local handle and its improvements and drawbacks.
Limitations of scoped thread local
- Whether a variable is initialized is check at runtime, adding overhead and possibilty of panics for each access.
- Usage of closures to access globals is extremely verbose. Because thread locals are not exactly 'static, they must be accessed with the
LocalKey::with
method.
A new approach: Thread local handle
Instead of hiding the context as a static import, you would use a ZST handle with lifetime to hold the fact that the thread local is initialized. This idea is based on that most API designs has a struct store either a Rc or reference to “parent” context, and when we want to reduce the overhead per object thread-local storage becomes a good fit.
Benefits
- Initialization is ensured at compile time
- You pass around a lifetime-annotated struct so you don’t need the noisy closures to access TLS
- Maybe more clear that a context exist
Drawbacks
- This approach doesn’t work across thread. Any struct that includes the context is effectively fixed to the thread it was created. (A possible approach is to use some auto-trait juggling to make a safe API, another is just use unsafe + guideline to workaround)
- As the handle doesn’t contain any data, passing it around could also be seen as unnecessary syntax overhead (although still less than passing as function argument)
The primary motivation of this proposal, as described at the beginning, is to reduce syntax overhead as well as enabling use of the context in traits. Whatever approach we’re going to use, I believe this would improve the ergonomics of working with the compiler. How do you think?