Skip to content

Rationalize conversions throughout combinators #291

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

Closed
aturon opened this issue Dec 14, 2016 · 5 comments
Closed

Rationalize conversions throughout combinators #291

aturon opened this issue Dec 14, 2016 · 5 comments

Comments

@aturon
Copy link
Member

aturon commented Dec 14, 2016

There are a number of possible "liftings" and conversions that combinators can allow:

  • Working with T, vs Result<T, E>, vs Future<Item = T, Error = E>, vs IntoFuture<Item =T, Error = E>. The current combinators are a mix.
  • Allowing for error conversion via From/Into.

We recently added a combinator specifically for the latter.

In general, though, it'd be nice to make the combinators consistent and maximally flexible -- but it's easy to run into problems with type inference. Let's iterate on this.

@aturon aturon added this to the 0.2 release milestone Dec 14, 2016
@dwrensha
Copy link
Contributor

Automatic conversion between error types sounds scary to me.

I think we will likely want to have something like

impl <T, E> ::std::ops::Carrier for Box<Future<Item=T,Error=E>> {
    type Success = T;
    type Error = E;
    //...
}

so that we can conveniently use try!() / ? when working with futures. In such cases we will already have an automatic call to e.into(). If on top of that we also decide to add automatic conversion between error types, then we'll frequently get chained calls to .into(), and the typechecker will not be happy.

@alexcrichton
Copy link
Member

Another option would be to play around with blanket IntoFuture impls, and we could even enlist specialization depending on the various timelines in play here. I'm also quite interested to see if we can leverage ?, but I'm also somewhat dubious we could get it to work.

I agree with @dwrensha that too many silent conversions could get unwieldy, but in general I think it's fine to inject From::from in tons of places as it's what ? is doing anyway (at least on the error side)

@seanmonstar
Copy link
Contributor

With the current proposal for the ? trait, it's half-way possible to work with something like tokio.

This would be possible:

impl QuestionMark<Async<T>, io::Error> for io::Result<T> {
    fn ask(self) -> Poll<T, io::Error> {
        match self {
            Ok(v) => Ok(Async::Ready(v)),
            Err(e) => match e.kind() {
                io::ErrorKind::WouldBlock => Ok(Async::NotReady),
                _ => Err(e),
            }
        }
    }
}

However, like I said, it only gets us half-way.

let something = self.inner.poll()?;

The above will make something of type Async<T>, so you still need to match and then return the NotReady case.

To get this to work, it seems 2 directions could be taken:

  1. Get the QuestionMark (Carrier/Try) trait to not use Result<T, E>, but something that allows the de-sugaring to return even when Ok(Async::NotReady).
  2. Move the idea of NotReady back in to the Err case, similar to how WouldBlock is an error case.

Of course, the choice to do neither could be taken, but seems like then we miss out on an excellent language feature, ?.

@kevincox
Copy link
Contributor

The ? is in stable now, it would be really nice to be able to use this for futures. I end up temped to wrap my functions in Result<_, Future> so that I can use ?.

@alexcrichton
Copy link
Member

#733 has landed on 0.2 which blanket removes From conversions for now, so I'm going to close this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants