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

Generic Futures #3434

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Generic Futures #3434

wants to merge 5 commits into from

Conversation

p-avital
Copy link

@p-avital p-avital commented May 22, 2023

This RFC proposes adding a (defaulted) generic parameter to the core::future::Future trait to allow more flexibility in Future::poll's second argument (context).

This is would allow new Wakers to be created, that may be used to:

  • Allow the creation of ABI-stable wakers, allowing futures constructed by a shared object to be run on another's executor.
  • Allow wakers to adopt other structures that that of vtable/pointer pairs, which may be desirable to certain domains.
  • Allow specific futures to rely on additional behaviour of specific wakers that certain executors may provide.

Rendered

@p-avital p-avital changed the title Start the generic-futures RFC Generic Futures May 22, 2023
@VitWW
Copy link

VitWW commented May 22, 2023

Nice try!
It looks like you miss sections "What is now impossible(or extremely complicated)" and "How new proposal solves this complications".

@p-avital
Copy link
Author

Nice try! It looks like you miss sections "What is now impossible(or extremely complicated)" and "How new proposal solves this complications".

Cheeky, I actually went and checked the template again x)

For reference, here's a RFC I previous opened on trying to make the current Waker ABI stable without causing breaks in the std library. Unfortunately, doing so would impose a runtime cost on every program that uses futures, regardless of whether or not they care about ABI stability, which doomed said RFC.

With this proposal, new wakers can be created to fit any design constraint we please, provided they have interior mutability (and by adding a waker_mut accessor to Context, even that restriction could be lifted).

@ehuss ehuss added the T-libs-api Relevant to the library API team, which will review and decide on the RFC. label May 25, 2023
@Jules-Bertholet
Copy link
Contributor

@rustbot label A-futures

@rustbot rustbot added the A-futures Futures related proposals label May 25, 2023
@coolreader18
Copy link

The desugaring of async functions/blocks seems under-spec'd to me. Like, if async fn foo() desugars to fn foo<_W>() -> impl Future<_W, Output = ()> where SomeSubFuture: Future<_W>, then any async block depending on foo would have to have some sort of way to specify where foo<_W>; that the generic matches the bounds in another function's where clause.

@p-avital
Copy link
Author

Indeed, this makes desugaring to RPIT impossible without adding a generic argument to the funciton.

Ideally, it would desugar to fn foo() -> impl for<_W: _WakerTrait> Future<_W, Output = ()>, for this use of for only works for lifetimes (unfortunately). This means RPIT is insufficient to express async fn.

But to my knowledge, it is fn foo() -> impl Trait that desugars to fn foo() -> AnonymousType where AnonymousType can't be named, and only exposes the Trait bound.

So I think async fn foo() should straight up skip the impl Future step of desugaring, immediately going to the AnonymousType representation.

@jan-hudec
Copy link

But to my knowledge, it is fn foo() -> impl Trait that desugars to fn foo() -> AnonymousType where AnonymousType can't be named, and only exposes the Trait bound.

In other words to be more accurate it desugars to fn foo() -> AnonymousType where AnonymousType : Trait. The where is importnat.

So I think async fn foo() should straight up skip the impl Future step of desugaring, immediately going to the AnonymousType representation.

And you still have the same problem, because it is the where for<_W: WakerTrait> AnonymousType : Future<_W, Output=()> that you still can't write.

… and if the poll method was generic instead, the trait would stop being object safe, so it would stop working in a Box and that is also essential.

@p-avital
Copy link
Author

p-avital commented Jun 4, 2023

But to my knowledge, it is fn foo() -> impl Trait that desugars to fn foo() -> AnonymousType where AnonymousType can't be named, and only exposes the Trait bound.

In other words to be more accurate it desugars to fn foo() -> AnonymousType where AnonymousType : Trait. The where is importnat.

On the contrary, the where clause isn't important, because AnonymousType does implement Future<_W> for the open set of _W with the appropriate bounds. Anonymous types tend to put us in "we have to tell the function what the type implements" mode, but you've never had to write fn foo() -> String where String: Display, have you? To the compiler, AnonymousType is no different from String, it's just that we can't name it.

I've updated the RFC to make these anonymous type shenanigans more readable. Thanks for the input :)

@Fishrock123
Copy link
Contributor

Your rendered link is broken

@p-avital
Copy link
Author

p-avital commented Jun 8, 2023

Your rendered link is broken

Thanks for notifying me, it should be fixed now :)

Comment on lines 3 to 4
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/3434)
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your "Rendered" link in the first comment of this pull-request is broken

Copy link

@VitWW VitWW Jun 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ops, it looks I forgot to "comments" my "Pending" review several days (

@e-dant
Copy link

e-dant commented Jul 29, 2023

The core::task::Waker type is the common denominator to all interactions with futures, making adjusting its API and implementation especially trying, as it affects the whole ecosystem indiscriminately

I'd think that changes to wakers and futures would consider a way to leave some room for completion-based (as opposed to readiness-based) asynchrony.

Maybe that's outside of the scope here. Maybe not.

@yoshuawuyts
Copy link
Member

We should probably nominate this for the @rust-lang/wg-async triage. I don't think we have a label for that here, but tagging us so we can track it.

@p-avital
Copy link
Author

p-avital commented Feb 14, 2024

Thanks @yoshuawuyts

If anyone knowledgeable is reading this, I'm looking for some help in prototyping this RFC. I'm not familiar with the rustc's codebase, and it looks nothing like proc-macros which is about where my knowledge of code-generation in Rust ends, so any guidance would be appreciated 😅

I'm looking at modifying StateTransform::run_pass, or maybe transform_async_context, or maybe I'm looking completely at the wrong place... Please send help 😅

@traviscross traviscross added I-async-nominated Indicates that an issue has been nominated for prioritizing at the next wg-async triage meeting. WG-async Relevant to the async working group. labels May 26, 2024
@tema3210
Copy link

tema3210 commented Jul 12, 2024

Ideally, it would desugar to fn foo() -> impl for<_W: _WakerTrait> Future<_W, Output = ()>, for this use of for only works for lifetimes (unfortunately). This means RPIT is insufficient to express async fn.

That desugaring cannot be made into a concrete type, so most likely this: fn foo<_W: _WakerTrait = std::task::waker>() -> impl Future<_W, Output = ()> would work.

and if so, potential executor trait can be given an assoc type for precisely its context, then we can have

trait Future<E: std::task::Executor> { 
   type Output;
   fn poll(self: Pin<&mut self>, cx: E::Ctx) -> Poll<Self::Output>; 
}

In the air: adapter between executors so that it's possible to have more than one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-futures Futures related proposals I-async-nominated Indicates that an issue has been nominated for prioritizing at the next wg-async triage meeting. T-libs-api Relevant to the library API team, which will review and decide on the RFC. WG-async Relevant to the async working group.
Projects
None yet
Development

Successfully merging this pull request may close these issues.