FusedFuture is incoherent
Opened this issue · 0 comments
The documentation for FusedFuture
is quite vague. Unfortunately, I think this vagueness has enabled incoherence to arise and the situation is now rather poor:
Some reasoning
I think let r = select!{ r = fut => r };
should work the same way as let r = fut.await;
. Otherwise select!
's behaviour is inconsistent with the behaviour of the supplied futures.
select!
doesn't poll any futures whose FusedFuture::is_terminated
returns true
.
This means that FusedFuture::is_terminated
must not return true
if the future would return Ready
; nor if it would squirrel away a Waker
from the Context
.
select!
's complete =>
feature relies on is_terminated
. The documentation is not entirely clear, but certainly is_terminated
there must return true
if the future has already returned Ready
.
The most reasonable interpretation of all this is_terminated
should return precisely whether the future has already returned Ready
.
However, many futures in futures-rs
implement FusedFuture
despite being unable to answer this question definitively. For example, OptionFuture
, oneshot::Receiver
and probably others. Others answer it wrongly: for example, future::Pending
has is_terminated
always return true
and this is even used in a test case (async_await_macros.rs
, select_with_complete_can_be_used_as_expression
).
Options
-
Declare
FusedFuture::is_terminated
is supposed to say precisely whether the future has returnedReady
. Remove the impls for futures that don't know whether they've already returnedReady
(which is many of them) and have users who need this functionality call.fuse()
. Fixfuture::Pending
. etc. This is an API break. -
Leave
FusedFuture::is_terminated
as it is, but plaster it, andcomplete =>
, with big warnings saying it's deprecated. Haveselect!
withoutcomplete
not ever callis_terminated
. This fixes the behaviour ofselect!
to be cosistent withawait
, and leaves users ofcomplete
alone. This is arguably a bugfix, although it might need a crater run or something. It seems like a practical approach to making this better, pending the probably still-long-distant 1.0 release. -
As 2, then: Introduce a new version of
complete
with a new name and a new trait to support it. For use in tests and corner cases, introduce a new "always looks like it has been awaited" future which is alwaysPending
and (unlikefuture::Pending
) is always "complete" for the purposes ofselect!
. -
Tell everyone to use Tokio which doesn't have these bugs.
References
#1989 request for select!
to work without FusedFuture
, based on conditional branches (which Tokio's select!
has). Fairly extensive discussion of some other problems with FusedFuture
.
#2475 report of brokenness with oneshot::Receiver
#2455 report of confusion with OptionFuture
and Pending
#2213 trouble with future::Map
FusedStream
This trait is very similar to FusedFuture
. My examination of the source in futures-rs
suggests that at least some of its impls have similar bugs to the bugs in the impls of FusedFuture
. But I haven't investigated FusedStream
properly and don't really know why it exists (and why it has a different API approach to FusedIterator
)