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

how to init with async method #108

Closed emacsist closed 3 years ago

matklad commented 4 years ago

Good question! At the moment, OnceCell provides only blocking API. async API seems plausible, but I don’t immediately know what it should look like exactly, as I am not async expert. I think it makes sense to implement this as a new crate, asyn_once_cell, at least initially.

asnimansari commented 4 years ago

@emacsist https://stackoverflow.com/questions/62351945/alternative-to-using-await-with-lazy-static-macro-in-rust Check if this can help you

timothee-haudebourg commented 3 years ago

I'm also interested in having async initialization functions. This seems pretty straight-forward to implement, at least for the unsync version of OnceCell. For example, the async version of get_or_try_init looks almost exactly like the original version (with a bit more type annotations):

pub async fn get_or_try_init<I, F, E>(&self, init: I) -> Result<&T, E> where I: FnOnce() -> F, F: Future<Output=Result<T, E>> {
    if let Some(val) = self.get() {
        Ok(val)
    } else {
        let val = init().await?;

        assert!(self.set(val).is_ok(), "reentrant init");
        Ok(self.get().unwrap())
    }
}

Do you still believe this require writing another crate for this? I could do it, but I'm afraid it would just be a copy-paste of this crate with some await added.

matklad commented 3 years ago

I've thought about this some more, and now I think it would be a bad idea to provide async version of get_or_init. If you need asyc_get_or_init, than there's an await inside the closure. That means that, mid-initialization, the closure would get suspended, and whatever code will be run instead. This code may try to init the same cell and block (that is, get needs to be async as well). This I think would be surprising, and a manual call to get / set would probably be less confusing about runtime semantics.

With that in mind, the decision is that async is explicitly out of scope for once_cell. I might be wrong, of course, the good way to prove that is to publish an async_once_cell to crates.io and to show that in practice the problems are not as big as I fear. I'll gladly link the crate from readme.

EvanCarroll commented 3 years ago

I found out I could use block_on to skirt this issue,

https://stackoverflow.com/questions/62351945/alternative-to-using-await-with-lazy-static-macro-in-rust/67354043#67354043

MikailBag commented 3 years ago

Tokio also provides asyncified OnceCell: https://docs.rs/tokio/1.5.0/tokio/sync/struct.OnceCell.html.