I've been using lazy_static on types which are not Send, but Sync, and when I tried to switch to LazyLock after updating a compiler I started getting cannot be sent between threads safely errors.
And, I mean, I do not intend to Send the value between threads!
Is there anything I can do to make this code compile?
Here is an example of what I am trying to achieve.
In the real world the code I am writing a library for is not thread-safe, and trying to invoke the functions on the code actually has static asserts verifyinig that the execution thread is correct (there are some other tricks like passing a sentinel which can only be retrieved on a lib thread) -- this allowed me to safely mark similar types Sync. I know I could have used thread_local, but ergonomically for users it was way better not having to deal with with.
I know I can achieve this with an additional layer of indirection, but it would be nice if I could avoid &static.
Would be glad for any help or comments!
It seems like the problem is that lazy_static, being a macro, can know that it is creating a value that is always going to be accessed via & (not even ever dropped), but LazyLock, being a type that has uses independent of the static item declaration, can't make that assumption and so has to have a Send bound. In particular, if LazyLock had a more relaxed Sync implementation, one could do this with a LazyLock<Foo> where Foo is not Send:
Thread A: Create LazyLock<Foo>.
Thread A: Pass &LazyLock<Foo> to thread B.
Thread B: Cause initialization of the LazyLock, executing the initialization function on thread B.
Thread B: Drop the &LazyLock<Foo> borrow.
Thread A: Call LazyLock::into_inner(), or just drop the LazyLock<Foo>, thus dropping the Foo too.
Oops, the Foo has been sent from B to A.
When you use Box::leak() to make &'static CppProperty you're effectively adding back the promise that CppProperty won't ever be dropped.
I don't know of an ideal solution here. You could keep using lazy_static, or you could write your own macro that constructs a static and uses an unsafe wrapper to regain the required Send while still using std::sync::LazyLock as the underlying laziness implementation. (Given the choice, I'd keep using lazy_static, for now.) But perhaps someone else can think of a cleverer solution.