-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
standard lazy types #2788
standard lazy types #2788
Conversation
Co-Authored-By: Mazdak Farrokhzad <[email protected]>
Great RFC, I hope it makes it into the standard library! One other aspect that the crate /// Never blocks, returns `None` if uninitialized, or while another thread is initializing the `OnceCell` concurrently.
pub fn get(&self) -> Option<&T>;
/// Never blocks, returns `Err` if initialized, or while another thread is initializing the `OnceCell` concurrently.
pub fn set(&self, value: T) -> Result<(), T>;
/// Blocks if another thread is initializing the `OnceCell` concurrently.
pub fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
;
/// Blocks if another thread is initializing the `OnceCell` concurrently.
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
where
F: FnOnce() -> Result<T, E>,
;
} Alternatively, all four methods could be blocking, and a But don't let this comment derail the discussion about whether to include |
It looks like rust-lang/rust#63065 will allow using a zero-size closure type in a static: static FOO: Lazy<Foo, impl FnOnce() -> Foo> = Lazy::new(|| foo()); But this will require spelling the item type twice. Maybe that repetition could be avoided… with a macro… that could be named |
@SimonSapin or we can add bounds to struct Lazy<F: FnOnce<()>> { .. } and use it like this, static FOO: Lazy<impl FnOnce() -> Foo> = Lazy(foo); |
@KrishnaSannasi How does that help with the requirement that static FOO: &[_] = &[2, 4]; Compiling playground v0.0.1 (/playground)
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> src/lib.rs:1:15
|
1 | static FOO: &[_] = &[2, 4];
| ^ not allowed in type signatures |
@SimonSapin I'm not sure what you are asking, I didn't use You proposed using |
It doesn't really seem all that worth it to me to spend time worrying about how to inline a function that is called at most one time in the entire execution of a program. |
A small difference that may be worth noting: |
@pitdicker pointed out that we actually can have some part of the |
text/0000-standard-lazy-types.md
Outdated
Altogether, this RFC proposes to add four types: | ||
|
||
* `std::cell::OnceCell`, `std::cell::Lazy` | ||
* `std::sync::OnceCell`, `std::sync::Lazy` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that we have sync::Once
and cell::Cell
, but this may be confusing. Just a thought.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kinda like the combination of both, so the naming may be good (modulo Send
/Sync
concerns). But it would be better if the !Sync
version had a different name from the Sync
version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps acknowledging OnceCell
as a WORM (write once, read many) might make WormCell
be a better name? Assuming that the implementation isn't too sluggish.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also would really like to see there be a different name for these, rather than relying on the fact that they lie in two separate modules. Maybe just prefixing the sync implementations with Sync
is enough, i.e. SyncLazy
and Lazy
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be against WORM terminology, as it seems rather obscure: I don't think I see it often enough to not consult wikipedia. A more appropriate term would probably be SingleAssignmentCell
, but that's a mouthful.
Ultimately, I doubt that there's a perfect solution for cell/sync naming, so the libs team would have to just decide on some particular naming scheme. I am personally ok with Sync
prefix. The disadvantage of SyncX
scheme is that it makes more common case longer to spell, and is a tautology (sync::SyncOnceCell
).
I personally like the proposed cell::OnceCell / sync::OnceCell
variant the most:
- if you want extra clarity, you can qualify the type with
cell::
orsync::
on the call site, instead of importing it - due to how awesome Rust is, it's impossible to use
cell::OnceCell
instead ofsync::OnceCell
, and the mistake in other direction is not really a mistake: just a very slight perf loss - in practice, I think it would be rare for a module to use
cell
andsync
versions simultaneously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I like the way it's organized in the once_cell
crate with explicit sync::*
and unsync::*
modules.
The part that feels the most strange to me about this currently proposal is that a OnceCell
lives in both cell
(makes sense, since it's a type of cell), and sync
(makes sense, given that Once
is also defined here). Something's conflated here, though this could well be outside the scope of this RFC. Either way, this is the first "cell" added to the sync
module.
For another point of reference, we currently have Rc
defined in std::rc
and a similar Arc
defined in std::sync
. I might argue this would make more sense as std::rc::{Rc, sync::Arc}
, which would solve my issue with OnceCell
as well, though I don't expect this to be possible with backwards compatibility requirements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, another possibility is to introduce something like lazy and lazy::sync modules. As it stands, std::sync today feels a bit like, well, kitchen sync, it has a bit of everything.
I can imagine an alternative world, where std::sync is only for synchronization primitives, atomic and mpsc are top-level modules and Arc lives in rc. In this world, having an std::lazy module would definitely be better.
With current stdlib structure, std::sync::OnceCell blends better with the background.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, everything in std::cell
is !Sync
so it sort of maps to crates.io’s once_cell::unsync
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The libs team has discussed moving stuff out of std::sync into more appropriate modules (e.g. std::mutex::Mutex). I think ideally we wouldn't throw more stuff in there.
I was expecting this to implement haskell-style lazy values. Can I use this outside global scope? Maybe use another more descriptive name? like |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some changes from Once
/Lazy
to LazyCell
/OnceCell
/LazyLock
/OnceLock
, updated atomic ordering conclusion section
- Update LazyCell/LazyLock/OnceCell/OnceLock usage - Clarify stance on atomics - Some minor flow updates Co-authored-by: bl-ue <[email protected]>
Once_cell seems to be preferable method with path toward stabilization via rust-lang/rfcs#2788
Now that rust-lang/rust#105587 is nearing the end of this FCP, could this be either merged or closed? I would vouch for merging even if it isn't needed for any direct action. I see RFCs as a good way to document the intended use case - kind of nice to be able to look back at to see "what was the goal with this addition". But I also have no insight or sway into the RFC process so just do as is needed 🙂 |
As this is already stable on Special thanks to @tgross35 for pushing this over the finish line, Rust needs more heroes like you! |
You did all the hard work @matklad, I just did the easy part :) |
Nice to hear this. Does that mean users could take the new official version to replace |
edit: |
Add support for lazy initialized values to standard library, effectively superseding the popular
lazy_static
crate.Rendered