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

Async-closures or reference-parameterized-closures-returning-futures #78

Open
2 of 4 tasks
stuhood opened this issue Mar 21, 2021 · 3 comments
Open
2 of 4 tasks
Labels
good first issue Good for newcomers help wanted Extra attention is needed roadmap-topic Top-line goal for the roadmap status-quo-story-ideas "Status quo" user story ideas

Comments

@stuhood
Copy link

stuhood commented Mar 21, 2021

Brief summary

Not having async closures can mean needing to resort to macros to create certain (fairly common) types of combinators (ones where a closure that returns a future runs into lifetime issues).

We experienced this in pantsbuild/pants#11548, and I ended up writing a macro to put what would have been a parameter to a closure-returning-a-future or async-closure directly on the stack instead: pantsbuild/pants#11759

Optional details

  • (Optional) Which character(s) would be the best fit and why?
    • Alan: the experienced "GC'd language" developer, new to Rust
    • Grace: the systems programming expert, new to Rust
    • Niklaus: new programmer from an unconventional background
    • Barbara: the experienced Rust developer
  • (Optional) What are the key points or morals to emphasize?
    • Working reference-parameter-taking-closures-returning-futures would be great to have, but would require fairly advanced lifetimes (GATs?) to use even once they are possible (would likely be Barbara's choice). On the other hand, async-closures are less general, but likely to be easier to use (would likely be Alan's choice).
@stuhood stuhood added good first issue Good for newcomers help wanted Extra attention is needed status-quo-story-ideas "Status quo" user story ideas labels Mar 21, 2021
@nikomatsakis
Copy link
Contributor

@stuhood thanks for the example! I'd love to see a write-up dramatizing and spelling out some of the downsides of this macro approach you ended up with.

@alsuren
Copy link
Contributor

alsuren commented Mar 26, 2021

I can provide my own story. It's more of a saga, but contains two examples of this in two different projects. I would consider myself to be an Alan at the time, but it's a tale that involves a few other characters like Alan and Barbara. I will use real names and references, and once it's all written down we can trim it down and extract a persona story out of it.

David was using the gotham web framework for some toy projects since before async/await became stable. He was new to rust, and not using it professionally, but had a friend with experience contributing to the compiler that could help him. Gotham's examples were generally clear and well tested, and David enjoyed contributing to them, to show other people how to use the framework. Once async/await became stable, David contributed some examples of how to use async functions to handle http requests (gotham-rs/gotham#281 - first drafted in October 2018 on nightly, "finished" Feb 2020 and merged June 2020 after a maintainership change. This uncovered some ergonomics problems around boxing futures, so a helper method was added in the same PR, but that's unrelated to this ticket).

Since Gotham's API predates async functions, it historically required you to take ownership of the request context (fn handler(state: State)) and return it alongside your response in the success/error cases (Ok((state, response)) or Err((state, error))). This meant that you couldn't use the ? operator inside your http request handler. The answer was for the handler to take an &mut reference to State for the lifetime of the Future, but David couldn't work out how to express this.

In mid May, someone predictably raised a bug about ? (gotham-rs/gotham#431) and a few other Gotham contributors tried to get it to work but got stuck. When David tried it, the compiler diagnostics kept sending him around in circles. He could work out how to express the lifetimes for a function that returned a Box<dyn Future + 'a> but not an impl Future. David identified rust-lang/rust#45994 as a possible solution to the problem, but secretly longed to be able to say fn register_handler(f: impl async Fn(state: &mut State) -> Result<Response, Error> and have Rust elide the lifetimes for him). David even tried implementing this himself, but he didn't have anyone to help him, and eventually gave up.

Eventually, towards the end of June, someone found a forum reply by Alice explaining how to express what the Gotham team were after (higher order lifetimes and helper traits). This was picked up by the gotham team and merged in gotham-rs/gotham#450 .

In parallel with this, David helped the Goose team with a proof-of-concept port their http load testing tool to use async, tag1consulting/goose#8 but again ran out of steam before completing the work. The Goose team had a couple of shots at this, and problems storing the callback closure which borrowed some context (&User). Eventually, a reddit comment by Alice got them unstuck (higher order lifetimes and helper traits again), and they got it working in a later PR tag1consulting/goose#22 . They could use fns as callbacks, but not closures, and they needed a helper macro to box up the callback fn for ergonomics reasons. Once the Gotham fixes were approved and merged, David produced another proof-of-concept for Goose (tag1consulting/goose#94) which allowed them to use closures as well. This got picked up by the goose team in tag1consulting/goose#120 and merged.

I can write this up as a proper story PR if you want. I guess I'd want to boil the essence down to a single story involving an interaction between Alan and Barbara?

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Mar 31, 2021

That's really helpful @alsuren .. I'll take a look at #101 too, haven't gotten to it yet.

UPDATE: Oh, I guess I did.

@traviscross traviscross added the roadmap-topic Top-line goal for the roadmap label Jan 18, 2024
@traviscross traviscross added this to the DRAFT: Async 2024 milestone Jan 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers help wanted Extra attention is needed roadmap-topic Top-line goal for the roadmap status-quo-story-ideas "Status quo" user story ideas
Projects
Status: In Progress
Development

No branches or pull requests

4 participants