Skip to content
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

Temporary values do not outlive a direct await #63778

Closed
Marwes opened this issue Aug 21, 2019 · 4 comments
Closed

Temporary values do not outlive a direct await #63778

Marwes opened this issue Aug 21, 2019 · 4 comments
Labels
A-async-await Area: Async & Await A-lifetimes Area: lifetime related T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@Marwes
Copy link
Contributor

Marwes commented Aug 21, 2019

struct Test(String);

impl Test {
    async fn borrow_async(&self) {}

    fn borrow(&self) {}

    fn with(&mut self, s: &str) -> &mut Self {
        self.0 = s.into();
        self
    }
}

async fn test() {
    // error[E0716]: temporary value dropped while borrowed
    Test("".to_string()).with("123").borrow_async().await;
}

fn main() {
    // Temporary outlives the borrow() call
    Test("".to_string()).with("123").borrow();
}

https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=2649e4f172c54090d759b2f9484b31e1

A fairly common pattern is to use builder functions that takes &mut self and returns &mut Self so that multiple builder methods can be used in a row followed by building/using the final value. With normal, sync functions this works fine since the created temporary lives as long as the enclosing statement but if the final result is awaited on then we instead get an error.

This forces such builders to use moving functions fn (self) -> Self which can limit their use or to always write the builder as

let mut init = Init();
init.modify();
init.build();

Is it possible and/or planned that temporaries can be used in this way with await?

@jonas-schievink jonas-schievink added A-async-await Area: Async & Await A-lifetimes Area: lifetime related T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Aug 21, 2019
@Centril
Copy link
Contributor

Centril commented Aug 21, 2019

cc @matthewjasper @cramertj

@Marwes
Copy link
Contributor Author

Marwes commented Aug 22, 2019

Going with a moving API over &mut only helps if the value is also moved into future

https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=1c7aecd5a71c3bc18daf6936cf47fd22

For redis, where I encountered this it is possible to avoid capturing &self in the future by avoiding async fn but I may want to change the API in a way that &self needs to be captured. Such an API would only be ergonomic if await were changed in the manner described however.

Changing it would at least change the drop order for temporaries so this might be a stability hazard (maybe not since it doesn't compile?).

@Centril
Copy link
Contributor

Centril commented Aug 25, 2019

This seems like the same issue as #63832?

@nikomatsakis
Copy link
Contributor

Closing as a duplicate of #63832, I'll move the example over there though to be sure.

Marwes pushed a commit to Marwes/redis-rs that referenced this issue Oct 10, 2019
Marwes pushed a commit to Marwes/redis-rs that referenced this issue Oct 10, 2019
Marwes pushed a commit to Marwes/redis-rs that referenced this issue Oct 25, 2019
Marwes pushed a commit to Marwes/redis-rs that referenced this issue Dec 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await A-lifetimes Area: lifetime related T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants