After more than half years of rust in production i still dont understand how lazy_static works. What am I doing wrong?

I am using rust in prod for more than 6 months already and I feel like I got the most parts yet I still cannot replicate the behaviour of lazy_static by myself and I feel awful about it.
I just want to learn about your experiences. How did you get the details of such magic things? It sounds extremely simple just initialize a global pointer once and use it. I just have no clue what to do about it still.

1 Like

Basically, there are two things to know here:

  • there is a lazy initialization pattern (Lazy)

    Instead of holding a T, you hold an Option<T> (and maybe an impl FnOnce() -> T factory, unless you expect the factory to be explicitely given later). So the value is internally init with None, and the first time it is queried (through a function / method call), it is replaced with Some(factory()).

    Now, since we will want to have such thing in a static, which requires Sync-ness and does not provide &mut _ access (only &_), then Sync-hronised interior mutability is required. So it's rather something like RwLock<Option<T>>

  • there is a static variable (Deref trick, c.f., link below)

    now the Lazy value can be used in a static context, but to give an API to users where the method call is "invisible", a trick / hack is used:

    • a proxy zero-sized struct occupies the name of our lazy_static, but has a Deref implementation which dereferences to an internal / hidden Lazy which is the thing that actually contains our (lazy) expression. It is within that deref() method that the Lazy "get or init" pattern is called each time our lazy_static is referred to.


* it turns out they use a Cell<Option<T>> instead of an UnsafeCell<Option<T>> since it offers the ergonomic Cell::set, but it is still an unsafe construct in a Sync context, hence the need for a manual Sync-hronization based on Once. They have a FIXME to replace Option<T> with MaybeUninit<T>, but since they use the unreachable_unchecked hint on the None case, the program behavior should be the same, it may just waste one byte, which is not a big deal for a global variable.
3 Likes

I think i understand the thing a bit i will today try some stuff with unsafe dereferencing the pointer and stuff lets see if i will figure the thing out :slight_smile: thnak you so much for the answer

You can look at once_cell's implementation of Lazy to get a macro-free version of lazy_static. It maybe easier to follow.

3 Likes