Size of std::lazy::Lazy

It seems as if Lazy has a larger size than necessary.

Here is the current definition:

pub struct OnceCell<T> {
    // Invariant: written to at most once.
    inner: UnsafeCell<Option<T>>,
}

pub struct Lazy<T, F = fn() -> T> {
    cell: OnceCell<T>,
    init: Cell<Option<F>>,
}

Either cell or init will be empty, but Lazy<T, F> still needs the memory of T and F combined. An alternative might be an OnceCell that takes two types:

enum OnceCellContent<T, U> {
    Init(T),
    Uninit(U)
}

pub struct OnceCell<T, U> {
    // Invariant: written to at most once.
    inner: UnsafeCell<OnceCellContent<T, U>>,
}

pub struct Lazy<T, F = fn() -> T> {
    cell: OnceCell<T, F>
}

I didn't find any previous discussion about the size of Lazy, so perhaps I've missed something and this would be a bad idea for some reason. Or what do you think?

2 Likes

That would work, although you'll need three states:

enum LazyState<T, F> {
    Init(T),
    Uninit(F),
    InitInProgress,
}

See also rfcs/0000-standard-lazy-types.md at std-lazy · matklad/rfcs · GitHub.

This is not done mainly for simplicity -- there are a bunch of higher-priority design questions to nail down: Tracking Issue for `once_cell` · Issue #74465 · rust-lang/rust · GitHub

3 Likes

Ah, I see. Well, one could mention in the RFC that OnceFlipCell would enable a more memory-efficient design of Lazy. But I agree, OnceFlipCell could be introduced even after stabilizing OnceCell and Lazy, so it can be thought about later. Thank you!

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.