[pre-RFC] lazy-static move to std

Trying to decide where lazy_static belongs now that the stabilization is complete. One potential proposal is to move it to std. This proposed RFC is to begin that process. I’m looking for guidance before I submit this RFC.

Currently lazy_static is in the nursery, and in November it was released as 1.0

Should I submit this RFC?

3 Likes

If it’s being moved to a core part of the language, maybe it could also get a first-class syntax without a macro wrapper?

edit: There’s thread_local! in std already, so macros around definitions are already a pattern.

1 Like

Contextual lazy keyword! At least, I don’t want a #[lazy] attribute personally, since I think it’s a reasonable expectation that any first-class lazy-init mechanism will require non-trivial codegen, and having an attribute change the core semantics of an item is… undesireable (see #[async]).

In 2015, when lazy_static was moved to the nursery, concerns about documentation for blocks generated by a macro was raised.

Is this still relevant? lazy_static! has no problem preserving the documentation of the single public item it creates, because doc comments are handled as attributes in macros.

2 Likes

See also Helper for most common use of `std::sync::Once`.

2 Likes

It’s quite likely I missed something here, but I was under the impression that the consensus in Rust (as it is in the Python ecosystem) was that, at least in practice, stdlib is where libs go to die? If that is true, would a move like this not be ill-advised?

const fn adds an interesting wrinkle here: because calling const fn is stable, but defining them is not, we can have better API by adding this to stdlib (sort-of how futures are added to core as well).

2 Likes

ಠ_ಠ What gave you that impression?

2 Likes

The very strong bias against putting significant new functionality in stdlib, at least in practice. The only additions I’ve seen all year (perhaps even longer than that) are only relatively tiny API tweaks and additions, and things like Pin which are so fundamental that they cannot feasibly live anywhere else.

In addition, the logic seems sound: a std library cannot easily iterate on API’s as backwards-compatible API breakage is a big no-no. Meanwhile, random libs can do whatever they want, and thus are much more suitable to evolution.

Correct. std is not a dumping ground for features that are not fundamental to using Rust. Hence why the available collections are sparse, and why there's a TCP socket but no HTTP server (unlike, say, the Java std). New functionality is added by RFC, because everyone (except for #![no_std] crates and the embedded people) links std.

Not all libs are "random libs". Quite a few crates, which include things more languages have as part of their std, are controlled directly by Rust itself (see rand, regex, num, and the pseudonymous lazy-static). The only reason they're out-of-tree is because they are not tied to Rust's six-week release schedule. These crates make similar breakage guarantees though, by way of "an almost fanatical devotion to" semver, which is the Rust way.

Mind, I believe that things like random number generation, a regex engine, and a math library do not belong in std. Rust is not batteries included. lazy-static, however, is such a simple and widely-used feature that an argument can be made for putting it in std. Hence the bikes we are presently shedding.

I wasn't arguing that stdlib should be fatter, in fact I am a proponent of the current approach as it seems the more future-proof approach.
I was merely replying to

:slight_smile:

I also didn't mean to offend with the random libs comment. I meant that crates in general have more freedom than stdlib, and rightly so.

As for the stability guarantees, regex has passed the big 1.0.0 so there I'd expect stability, but rand is currently at v0.5.4 so per standard semver there I do not. If the crate enjoys 1.0.0-like stability then the version number should reflect that, no?

1 Like

Sorry, I didn't mean to come off as calling you out! I was mostly pointing out something that I thought was non-obvious for the longest time (that the "standard library" is really a large number of libraries, most of which are not linked by default), for the benefit of anyone reading this. A lot of people erroneously believe Rust has the same problems npm has with regards to important libraries being out of the platform's control, which draws unfair comparisons between npm and cargo, which are very different tools.

Personally, I believe "Rust is not ready yet", insofar that it is not "feature complete"; a lot of features someone coming from C++ (which the friend of mine who coined the phrase is) think to be incomplete or missing (his cited example was lambdas in constexpr^W const position); this includes support for things like RNG! I think Rust as a ecosystem is quite a few years ago from "being ready", in this sense.

1 Like

Given the availability of const fn, what use cases does lazy_static still have that const fn can’t cover?

1 Like

IIUC const fns can’t use heap allocation and will not be able to in short/mid term.

1 Like

One of the most common uses I have for lazy static is for regexes. Is const fn capable of supplanting that use case? (I genuinely don’t know. I’ve heard from some folks that it should be theoretically possible.)

Overall though, I do think lazy static belongs in std.

2 Likes

Miri can already do heap allocation. So getting them into const fn is mostly a matter for writing and accepting a bunch of RFCs, the implementation is already there.

Oh, and we should get const fn stabilized at some point...

Which kind of language features does that need? For example, everything HashMap does should work fine in const fn (though some of it is "unconst").

1 Like

It would probably make sense to defer inclusion of lazy_static in std until it’s clearer where the limits of const fns are in practice.

6 Likes

Regardless of decisions about moving to std vs. waiting on const fn, whether it’s OK to leave the no_std implementation as a polyfill on crates.io, etc, it would be great if some changes that are currently pending a crater run could get a chance to merge, release, and bake for a little while before lazy_static goes into core/std.

@RalfJung while you’re asking about needed language features, I would also add that recently I have been writing a bunch of code that depends on calling opaque FFI functions (either directly or indirectly) from inside lazy_statics. I have not been tracking the RFCs and implementation of const_fn, but I feel somewhat safe in assuming that the feature will not be including the ability to call unsafe extern "C" functions. It’s not clear to me that this use case (plus others which are also more niche than “const_fn isn’t stable yet”) would have lazy_static as an important enough crate to move into std (and hopefully core at that point, I think leaving that feature split between std/crates.io for std/no_std would be :frowning:).

And how const fn() -> Vec<u8> should work? Will this return vector initialized on start of the program or will somehow be stored in data segment of the binary?