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

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?

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 Likes

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!

Hi Alex, you said

Additionally, if you were to use impl Future you also wouldn’t require the bounds

could you please give a simple sample?

I saw your another post on https://github.com/rust-lang-nursery/futures-rs/issues/657
you said methods -> impl Future was not a good idea

The answers on this thread seem deprecated. What is the alternative to futures::done now?

futures::future::ready(value) or async move { value }

2 Likes

This topic was automatically closed after 91 days. New replies are no longer allowed.