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

Simpler selection futures #2112

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

Conversation

Lucretiel
Copy link
Contributor

@Lucretiel Lucretiel commented Apr 2, 2020

This pull request adds first, first_all, and first_ok. These are selection functions, similar to the existing select and friends, which (unlike select) don't return the incomplete futures after finishing (simply discards them instead). This allows them to have implementations that are simpler, have less overhead, and do not require Unpin on their contents.

This pull request is in progress:

Fixes #2031 and #2110

- Removed FusedIterator; .fuse() is equivalent.
- FirstOk is more explicit about its use of FusedIterator.
- This design will have to wait for rust-lang#2111 to be resolved; currently the
  contract of FusedFuture is not strict enough for our needs.
@Lucretiel
Copy link
Contributor Author

The remaining test failures seem unrelated to these changes

@cramertj
Copy link
Member

This looks good to me, though the dependence on #2111 worries me because I don't feel like I have a good handle on the best way to resolve that tension. Thanks for all your hard work here, though-- these combinators do look conveniently simpler.

Copy link
Member

@taiki-e taiki-e left a comment

Choose a reason for hiding this comment

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

Sorry for the delay reviewing. I have a few suggestions, but this looks good overall.

Comment on lines +18 to +19
unsafe_pinned!(future1: F1);
unsafe_pinned!(future2: F2);
Copy link
Member

Choose a reason for hiding this comment

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

Please use pin_project instead of pin_utils::unsafe_pinned. (Since #2128, we have been using it.)

pub struct FirstAll<F> {
// Critical safety invariant: after FirstAll is created, this vector can
// never be reallocated, in order to ensure that Pin is upheld.
futures: Vec<F>,
Copy link
Member

Choose a reason for hiding this comment

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

I recommend to use Pin<Box<[F]>> + this helper function, instead of Vec<F> + Pin::new_unchecked

// Critical safety invariant: after FirstAll is created, this vector can
// never be reallocated, nor can its contents be moved, in order to ensure
// that Pin is upheld.
futures: Vec<F>,
Copy link
Member

Choose a reason for hiding this comment

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

Same here


impl<T, E, F> Future for FirstOk<F>
where
F: Future<Output = Result<T, E>> + FusedFuture,
Copy link
Member

Choose a reason for hiding this comment

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

I recommend to use Fuse instead of relying on FusedFuture, as I said in #2111.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I considered this, and if we remove FusedFuture entirely (like you suggested) then we can go this route, but I went with the trait here because many futures are "inherently" fused, so in the interest of zero-cost abstractions I thought it made more sense to just have the user call .fuse() only if they need to

Copy link
Member

@taiki-e taiki-e Oct 14, 2020

Choose a reason for hiding this comment

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

so in the interest of zero-cost abstractions I thought it made more sense to just have the user call .fuse() only if they need to

Patterns like newtype are certainly not zero-cost, but Fuse just adds a flag to indicate if the future is complete and I think the actual cost is very small.

Another reason I don't want to add new features that rely on Fused* traits is that they are very likely to be removed in the next major version. (see #2207)
Even if we add features that rely on Fused* traits, they will be changed to use Fuse or MaybeDone. And if users forget to remove .fuse() on update to new version, it will eventually be even more inefficient.

@taiki-e taiki-e added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author label Nov 3, 2020
@taiki-e taiki-e added A-future Area: futures::future and removed futures-util labels Dec 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-future Area: futures::future S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Simple version of select for just getting the first of two futures to resolve
3 participants