You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
try{}: What does homogeneity mean for Poll? #155368
Add a bound like type Residual: Residual<Self::Output, TryType = Self>; to the Try trait so that this can't happen any more.
that insists on separately-coloured residuals. This would require changing the residual types for Poll to be distinct, and to update the FromResidual implementations accordingly to continue to support stable things.
Give up and say "meh, whatever" and try { my_poll? } will give a Result or an Option.
Add a bound into the desugaring for ? or try { somehow that would enforce that it's usable only on Try types with full homogeneity
perhaps merge the branch+from_residual into one helper function that calls both but which has some extra where bounds
Which would, of course conflict with the two existing specific impls. Thankfully they are both still nightly-only otherwise that would be impossibly breaking for users.
Looking at where I've used the current impl
it does, sort of make sense ...
/// The future returned by [UdpStream::next]#[derive(Debug)]pubstructNext<'stream,constBUF_SIZE:usize>{stream:&'streammutUdpStream<BUF_SIZE>,}impl<'stream,constBUF_SIZE:usize>FutureforNext<'stream,BUF_SIZE>{typeOutput = Option<io::Result<([u8;BUF_SIZE],usize,SocketAddr)>>;fn poll(mutself:Pin<&mutSelf>,cx:&mutContext<'_>) -> Poll<Self::Output>{let this = &mut*self;let stream = &mut*this.stream;ready!(stream.poll_read_ready_unpin(cx)?);// <- ? on a Poll<Result<Self::Ok, Self::Err>> inside a ready!() expansion
calling ready!(poll_wrapping_result_T?) works inside a function returning Poll<Result<T>>
How could we get same usability and be consistent with Try and the rest of the std lib?
Option & Result both offer a transpose method as well as Result::ok()/Result::err()/Option::ok_or() for handling similar situations.
If we were ok (!) with Poll's assumption that people will always want to pull out the Result in a Poll<Option<Result<T>>> then it would be easy enough to add a similar Poll<Result<T,E>>::transpose(self) -> Result<Poll<T>,E> along with a Result<Poll<T>,E>::ok_or_pending(self) -> Poll<T> (etc...)
That would allow the example above to be explicit:
/// The future returned by [UdpStream::next]#[derive(Debug)]pubstructNext<'stream,constBUF_SIZE:usize>{stream:&'streammutUdpStream<BUF_SIZE>,}impl<'stream,constBUF_SIZE:usize>FutureforNext<'stream,BUF_SIZE>{typeOutput = Option<io::Result<([u8;BUF_SIZE],usize,SocketAddr)>>;fn poll(mutself:Pin<&mutSelf>,cx:&mutContext<'_>) -> Poll<Self::Output>{let this = &mut*self;let stream = &mut*this.stream;
stream.poll_read_ready_unpin(cx).transpose().ok_or_pending()?;
As a user I find this much better as I can also handle cases where I want to map a Poll<Option<Result::Err>> to Poll::Ready<None> as well as cases where I want to map to Poll::Pending
for full homogeneity would it be valuable to also extend trait Residual to require:
pubconst trait Residual<O>:Sized{/// The "return" type of this meta-function.typeTryType:[const]Try<Output = O,Residual = Self> + FromResidual<Self>;
^^^^^^^^^^^^^^^^^^
sadly, this would not (always) reduce the need to add a bound in generic code but it certainly would help with ensuring consistent implementations
Activity
try_blocks#154391MusicalNinjaDad commentedon Apr 26, 2026
Coming at this from the
TryperspectiveI would expect
my_poll?to be the equivalent ofready!(mypoll)- thus allowing theready!macro to go the same way that thetry!macro has.That would mean we had (possible typos as I'm doing this outside an IDE and deliberately spelling out the assoc types):
Which would, of course conflict with the two existing specific impls. Thankfully they are both still nightly-only otherwise that would be impossibly breaking for users.
Looking at where I've used the current impl
it does, sort of make sense ...
calling
ready!(poll_wrapping_result_T?)works inside a function returningPoll<Result<T>>How could we get same usability and be consistent with Try and the rest of the std lib?
Option&Resultboth offer atransposemethod as well asResult::ok()/Result::err()/Option::ok_or()for handling similar situations.If we were ok (!) with Poll's assumption that people will always want to pull out the
Resultin aPoll<Option<Result<T>>>then it would be easy enough to add a similarPoll<Result<T,E>>::transpose(self) -> Result<Poll<T>,E>along with aResult<Poll<T>,E>::ok_or_pending(self) -> Poll<T>(etc...)That would allow the example above to be explicit:
As a user I find this much better as I can also handle cases where I want to map a
Poll<Option<Result::Err>>toPoll::Ready<None>as well as cases where I want to map toPoll::PendingMusicalNinjaDad commentedon Apr 26, 2026
To answer the original question:
Try, butPoll(and even consider Poll's current implementation blocking to the stabilisation of Try)MusicalNinjaDad commentedon Jun 9, 2026
for full homogeneity would it be valuable to also extend
trait Residualto require:sadly, this would not (always) reduce the need to add a bound in generic code but it certainly would help with ensuring consistent implementations
camsteffen commentedon Oct 8, 2026
I wonder if we should have a lint that fires on
Tryimpls where the following occurs:In other words enforce that
Try+Residualshould "round-trip" a Try type back to itself.