What's the correct way to combine io::Result and futures::Future?


#1

Seems like there should be a trivial function to lift Error into an appropriate future? Something like this:

fn lift_io<F, A, B, C>(a: io::Result<A>, f: F) -> IoFuture<B>
    where F: FnOnce(A) -> C,
          C: Future<Item = B, Error = io::Error> + Send + 'static,
          B: Send + 'static
{
    match a {
        Ok(x) => f(x).boxed(),
        Err(err) => failed(err).boxed(),
    }
}

Also, it feels like I should be able to drop the Send + 'static bounds… Maybe if I holler @alexcrichton?


#2

You can certainly do this! An easy way might be:

futures::done(result).and_then(my_closure)

That is, you can convert any Result<T, E> into a Future<Item=T, Error=E> easily through the futures::done method, and then once you’ve done that you can chain on further computations like and_then.

The Send + 'static bounds here are actually required by the return type, IoFuture. This is an alias around Box<Future<...> + Send + 'static> which is where those requirements come from. This is part of the difficulty of returning futures where if you return a trait object you have to define the Send-ness or 'static-ness up front.

If you were to return a concrete type (e.g. AndThen<Done<A, io::Error>, F>) then you wouldn’t require either Send or 'static. Additionally, if you were to use impl Future you also wouldn’t require the bounds. You also optionally have the ability to return a non-Send trait object or even a non-'static one depending on what you’d like to do in this situation.

Lemme know if any of that’s confusing though, I may need to update the “returning futures” section of the tutorial in light of recent changes with the futures library :slight_smile:


#3

That’s perfect actually. I’ve just been trying to figure out how to make my own version of Done (which of course, given what I wrote above, is more like DoneAndThen, so it would have taken me quite a while to realise that error in design). Times like this I’m a little sad about the lack of something like Hoogle — I knew exactly what type the thing had to have, but finding it in the documentation was too much for my weekend brain :smiley:

As far as documentation goes, some code with realistic error handling, alternating between layers of io and futures, would be a nice addition. I have a Haskell background so naturally I knew to try to look for something like liftIO that would push things up the transformer stack, but that pattern might be a bit weird to other people. And even then I’m not sure that’s actually the idiomatic way to proceed here!