I’ve been using lazy_static until now but was trying to migrate to OnceCell. It seems I can’t have a OnceCell<Regex> even though I’m never calling mutable methods on the regex. I’m not even using multiple threads.

The error I’m getting is:

Any way to solve this or do I have to use OnceLock / continue using lazy_static? I don’t want to add the overhead of using OnceLock if not necessary.

  • orangesnowfox@lemmyrs.org
    link
    fedilink
    English
    arrow-up
    8
    ·
    edit-2
    1 year ago

    So, the error you’re getting here is that the static itself needs synchronization, multiple threads can try to initialize the OnceCell at once because this is a static (only one initialization function gets called, the rest have to block).

    consider an example like this:

    use regex::Regex;
    use std::cell::OnceCell;
    
    // this can't compile because of the code below.
    static INSTANCE: OnceCell<Regex> = OnceCell::new();
    
    fn main() {
        std::thread::spawn(|| {
            let foo = INSTANCE.get_or_init(|| Regex::new("abc"));
            // something that does something with `foo`
        });
    
        // uh-oh, this can happen at the exact same time as the above,
        // which is UB if this compiles (we have a data race).
        let foo = INSTANCE.get_or_init(|| Regex::new("abc"));
        // again something that does something with foo.
    }
    

    lazy_static uses a lock under the hood. Specifically, when std is available (when std isn’t available I think it uses a spinlock but I didn’t actually check) it uses https://doc.rust-lang.org/std/sync/struct.Once.html (not to be confused with OnceCell/OnceLock), which explicitly states it locks. As in the excerpt below:

    This method will block the calling thread if another initialization routine is currently running.

    The short answer is, yes, you have to use OnceLock if you want this in a static, and OnceLock does roughly what lazy_static does anyway.

    • danyel@lemmyrs.orgOP
      link
      fedilink
      English
      arrow-up
      4
      ·
      1 year ago

      First of all, thank you for this very elaborate answer. So that means OnceCell can never be used in a static but only as local variable / member variable? I see, that makes sense and also reduces its use cases by a lot of what I initially thought. But your example makes sense and the name/package also suggest it’s not thread-safe in itself, I had just wrongly assumed OnceCell was meant to be used in static contexts.

      Thanks!

      • Aloso@lemmyrs.org
        link
        fedilink
        English
        arrow-up
        5
        ·
        1 year ago

        Yeah, it doesn’t help that in the once_cell crate, the thread-safe version was also called OnceCell; you had to choose between once_cell::sync::OnceCell and once_cell::unsync::OnceCell. But when it was added to the standard library, once_cell::sync::OnceCell was renamed to OnceLock to make them easier distinguishable. So