rust-lang-nursery / lazy-static.rs

A small macro for defining lazy evaluated static variables in Rust.
Apache License 2.0
1.89k stars 108 forks source link

Officially deprecate lazy_static #214

Open KodrAus opened 1 year ago

KodrAus commented 1 year ago

lazy_static has served the community well over the better part of a decade. Over that time, the Rust language has evolved, and better alternatives built on that evolution have emerged. That functionality has now made its way into the standard library, with aspects of it stabilizing from 1.70.0.

This library hasn't seen steady maintainership in some time. To support migration off lazy_static and towards once_cell or the standard library's types I propose we formally deprecate this library.

cc @rust-lang-nursery/libs-contributors

Fishrock123 commented 11 months ago

I think this library is still worth having, but with it's implementation switched to once_cell.

The interface of lazy_static is often much better for use cases where there isn't much worry of fallibility or misordering.

E.g. static regexes from string literals.

frewsxcv commented 7 months ago

I opened a PR for documenting in the README that one can now utilize the stable std::sync::OnceLock: https://github.com/rust-lang-nursery/lazy-static.rs/pull/216

lordofpipes commented 4 months ago

I think this library is still worth having, but with it's implementation switched to once_cell.

The interface of lazy_static is often much better for use cases where there isn't much worry of fallibility or misordering.

E.g. static regexes from string literals.

Are there currently any alternatives that provide a macro on top of std::cell::OnceCell and std::sync::OnceLock? It seems like LazyCell standardization is still being debated because of its usage of an extra function pointer to a closure at runtime.

frewsxcv commented 4 months ago

OnceLock is simple enough in my opinion. A macro would only save you a few characters, if any.

use std::collections::HashMap;
use std::sync::OnceLock;

fn hashmap() -> &'static HashMap<u32, &'static str> {
    static HASHMAP: OnceLock<HashMap<u32, &str>> = OnceLock::new();
    HASHMAP.get_or_init(|| {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        m
    })
}

fn main() {
    // First access to `HASHMAP` initializes it
    println!("The entry for `0` is \"{}\".", hashmap().get(&0).unwrap());

    // Any further access to `HASHMAP` just returns the computed value
    println!("The entry for `1` is \"{}\".", hashmap().get(&1).unwrap());
}
attackgoat commented 4 months ago

I would agree that OnceLock is simple enough that writing the get-function is trivial, but we're lazy and so @lordofpipes here is a macro rule for just that. It is a drop-in replacement for lazy_static which requires paste = "1.0" in order to generate the struct name:

macro_rules! lazy_static {
    ($name: ident: $ty: ty = $expr: expr) => {
        ::paste::paste! {
            struct [<__ $name:camel>];

            #[allow(unused)]
            static [<$name:upper>]: [<__ $name:camel>] = [<__ $name:camel>];

            impl ::std::ops::Deref for [<__ $name:camel>] {
                type Target = $ty;
                fn deref(&self) -> &Self::Target {
                    static S: ::std::sync::OnceLock<$ty> = ::std::sync::OnceLock::new();
                    S.get_or_init(|| $expr)
                }
            }
        }
    };

    {$(static ref $name: ident: $ty: ty = $expr: expr;)+} => {
        $(lazy_static!($name: $ty = $expr);)+
    };
}

Use it just like normal:

lazy_static! {
    static ref CARGO_MANIFEST_DIR: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    static ref OUT_DIR: PathBuf = PathBuf::from(var("OUT_DIR").unwrap());
}

...

let my_path = OUT_DIR.join("my-file.txt");

* This is poorly tested and likely rife with design issues, but it does work

Kimundi commented 4 months ago

For what its worth, I'dd support both deprecating the library, or turning it into a thin wrapper around the std types that make it obsolete.

smoelius commented 3 months ago

@KodrAus Is this still a "proposal," or is lazy_static now officially deprecated?

If the latter:

SimonSapin commented 3 months ago

Even if OnceLock makes the macro very simple, it’s still nice to have this macro somewhere reusable. https://crates.io/crates/lazy_static is a great place for it IMO.

smoelius commented 3 months ago

Even if OnceLock makes the macro very simple, it’s still nice to have this macro somewhere reusable. https://crates.io/crates/lazy_static is a great place for it IMO.

Sure. But notice that the version in this repo is 1.5.0, but the version published to crates.io is 1.4.0.

According to https://github.com/rust-lang-nursery/lazy-static.rs/issues/201#issuecomment-1142711977, @KodrAus does not have permissions to publish lazy_static to crates.io.

So even if someone rewrote this package as a wrapper around OnceLock, it's not clear that anyone could publish the new package to crates.io.

The only other alternative I can think of is if someone wanted to maintain a fork.

Kimundi commented 3 months ago

I was not aware that there is a permission problem here (which is unsurprising, seeing how the reason I originally shared ownership with the libs team was that I was unable to pay attention to my libraries consistently over time....)

@KodrAus - what do you need? Just the crates.io co-ownership?

KodrAus commented 3 months ago

@smoelius I think it's still a proposal, but it is effectively unmaintained in practice.

@Kimundi I think co-ownership would let me push the current changeset up to crates.io, which I'd be happy to do and look at addressing any bitrot we've accumulated in the last few years.

@SimonSapin what do you see as the value of this macro over a library like once_cell that offers the same functionality without needing a macro?

lordofpipes commented 3 months ago

what do you see as the value of this macro over a library like once_cell that offers the same functionality without needing a macro?

Like @attackgoat mentioned, it's still nice to be able to shorten it. The shortest equivalent still requires repeating the type definition twice. It's a macro I would have written anyways regardless of how it works under the hood, so if it were available as a 2.0 of this crate it might be nice. If not I'm not complaining either, keeping the current implementation and deprecating the crate is a more safe option anyways.

Kimundi commented 1 month ago

@KodrAus Sorry, another month went by too fast πŸ˜… I just sent you the crates.io ownership invite.

GameDungeon commented 3 weeks ago

While a bit niche, this crate is commonly used in #![no_std] projects. If this is deprecated an alternative will be needed.

This usecase makes swapping to a oncelock wrapper potentially problematic.

Edit: Looking at OnceCell, it might be a suitable alternative.

KodrAus commented 2 weeks ago

@Kimundi Sorry, it looks like I managed to miss this until the invite expired πŸ™ƒ Is there any chance of resending it? I can see us going around in circles a bit here though so if I ping a random member of the nursery team with permissions to push............ @cuviper could I trouble you to cargo publish the master branch here? It's all ready to go πŸ™

cuviper commented 2 weeks ago

Published!

KodrAus commented 2 weeks ago

Thanks @cuviper!