Skip to content

Tracking Issue for poll.ready()? #89780

Closed
@dtolnay

Description

@dtolnay
Member

Feature gate: #![feature(poll_ready)]

This is a tracking issue for the core::task::Poll::ready method, which combined with ? potentially supplants the ready! macro of #70922.

- let val = ready!(fut.poll(cx));
+ let val = fut.poll(cx).ready()?;

Public API

// core::task

impl<T> Poll<T> {
    pub fn ready(self) -> Ready<T>;
}

pub struct Ready<T> {...}

impl<T> Try for Ready<T> {
    type Output = T;
    type Residual = Ready<Infallible>;
    ...
}

impl<T> FromResidual for Ready<T> {...}

impl<T> FromResidual<Ready<Infallible>> for Poll<T> {...}

impl<T> Debug for Ready<T> {...}

Steps / History

Unresolved Questions

  • ?

Activity

added
T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
on Oct 11, 2021
ibraheemdev

ibraheemdev commented on Oct 11, 2021

@ibraheemdev
Member

One trivial item, should the debug implementation for Ready show the inner Poll<T>? I left it out initially without a good reason.

m-ou-se

m-ou-se commented on Oct 12, 2021

@m-ou-se
Member

One trivial item, should the debug implementation for Ready show the inner Poll<T>? I left it out initially without a good reason.

It doesn't matter much since it's unlikely that the Debug implementation for this type will be used much anyway, but the default #[derive(Debug)] implementation is probably fine here.

BurntSushi

BurntSushi commented on Oct 12, 2021

@BurntSushi
Member

Do we have a way of pinging async stakeholders here? There was a lot of discussion among several participants in #81050 for example. I can just pick out names from there, but if there's a better way...

m-ou-se

m-ou-se commented on Oct 12, 2021

@m-ou-se
Member

cc @rust-lang/wg-async-foundations

cramertj

cramertj commented on Oct 12, 2021

@cramertj
Member

Personally I find this less clear than the ready! macro:

With the .ready()? method

fn some_future_impl() -> Poll<Result<(), ()>> {
    some_check().ready()??;
    Poll::Ready(Ok(()))
}

fn some_stream_impl() -> Poll<Option<Result<(), ()>>> {
    some_check().ready()??;
    Poll::Ready(Some(Ok(())))
}

With the ready!(...) macro

fn some_future_impl() -> Poll<Result<(), ()>> {
    ready!(some_check())?;
    Poll::Ready(Ok(()))
}

fn some_stream_impl() -> Poll<Option<Result<(), ()>>> {
    ready!(some_check())?;
    Poll::Ready(Some(Ok(())))
}

The ?? in the former looks curious to me and it's not clear what order the various Try-like things are being processed (Result-like vs. Poll-like), while the latter looks more straightforward to me. That said, I also have a lot of experience using the system that exists today and never minded the ready! macro, so I'd appreciate hearing from folks who are newer to these APIs about their preferences.

ibraheemdev

ibraheemdev commented on Oct 12, 2021

@ibraheemdev
Member

You could write it this way:

fn some_future_impl() -> Poll<Result<(), ()>> {
    some_check()?.ready()?;
    Poll::Ready(Ok(()))
}

fn some_stream_impl() -> Poll<Option<Result<(), ()>>> {
    some_check()?.ready()?;
    Poll::Ready(Some(Ok(())))
}

Which makes it clearer IMO, because ? is generally used for Err propagation, and the .ready()? makes it clear that it is for Poll::Pending propagation.

The fact that there are two ways to use ? with Poll definitely adds complexity though.

LucioFranco

LucioFranco commented on Oct 14, 2021

@LucioFranco
Member

I have to agree with @cramertj I think the ready! macro provides a super clear "yield" point that the ready method does not have.

eholk

eholk commented on Oct 18, 2021

@eholk
Contributor

@rustbot label +AsyncAwait-triaged

added
AsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.
on Oct 18, 2021
songzhi

songzhi commented on Oct 21, 2021

@songzhi

In the coding experience aspect, since rust-analyzer supports custom postfix-snippets, just define a snippet like the following one, you can write ready! as postfix. But this snippet completion takes effect globally, maybe confusing and annoying when writing unrelative codes.

"rust-analyzer.completion.snippets": {
    "ready!": {
      "postfix": "ready",
      "body": [
        "ready!(${receiver})",
      ],
      "requires": "std::task::ready",
      "description": "ready!()",
      "scope": "expr",
    }
}
mjbshaw

mjbshaw commented on Jan 10, 2022

@mjbshaw
Contributor

Drive by comment: I have to disagree with statements that ready! is clearer. As someone relatively new to async stuff, I was reading some code that used ready!. Later, after some more review, I was surprised to learn that ready! affected the control flow of the function. I was not expecting that when I was reading the code. On the other hand, I know ? will affect the control flow: that's the whole point of the ? operator. I know this is subjective and others may not agree, but I wanted to add the experience of a non-async expert here. I'd love to see poll.ready()? stabilized!

46 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @eholk@joshtriplett@BurntSushi@nrc@m-ou-se

        Issue actions

          Tracking Issue for poll.ready()? · Issue #89780 · rust-lang/rust