matklad / once_cell

Rust library for single assignment cells and lazy statics without macros
Apache License 2.0
1.87k stars 109 forks source link

`Lazy` returning different results #224

Closed kpark-hrp closed 1 year ago

kpark-hrp commented 1 year ago

For unit testing, I have a const String that is randomly generated and shared.

const CLIENT_ID: Lazy<String> =
        Lazy::new(|| Alphanumeric.sample_string(&mut rand::thread_rng(), 16));

But it appears that Lazy is being evaluated multiple times and returns different String each call. I have a very basic equality check unit test to show this.

#[tokio::test]
async fn test_client_id() {
    assert_eq!(CLIENT_ID.clone(), CLIENT_ID.clone());
}
thread 'tests::test_client_id' panicked at 'assertion failed: `(left == right)`
  left: `"1ScRLmtGM8LcSHNJ"`,
 right: `"DezhUcYvnBbIOtyA"`', oauth/src/bin/authorizer.rs:201:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
kpark-hrp commented 1 year ago

It appears that replacing const with static fixes the issue.

static CLIENT_ID: Lazy<String> = Lazy::new(|| Alphanumeric.sample_string(&mut rand::thread_rng(), 16));

But, shouldn't const still behave the same way where the closure in Lazy is only evaluated once and shared?

kpark-hrp commented 1 year ago

It appears that this behavior is documented.

Note that the variable that holds Lazy is declared as static, not const. This is important: using const instead compiles, but works wrong.

But to me, this feels like an unintended behavior which should not compile

matklad commented 1 year ago

Yeah, it’s a known language level issue without good solutions, see https://github.com/rust-lang/rust/issues/40543

Stargateur commented 1 year ago

const is not named right, that more like macro in C, basically it's copy the expression and put it where you use it. That just a leçon that rust developer learn at some point, nothing is perfect.