Rust futures: an uneducated, short and hopefully not boring tutorial - Part 2
Tags: rust, averageprogrammer, async, futures
Published: 2017-11-03 09:00:38

---
title: "Rust futures: an uneducated, short and hopefully not boring tutorial - Part 2"
published: true
description: A quick review of Rust futures' common pitfalls.
tags: rust, averageprogrammer, async, futures
---

## Intro

In the [first post](https://dev.to/mindflavor/rust-futures-an-uneducated-short-and-hopefully-not-boring-tutorial---part-1-3k3) of the series we saw how to use futures in Rust. They are powerful and very easy to use, if done properly. In this second post we will focus on common pitfalls and, hopefully, how to avoid them.

## Error troubles

Chaining futures is easy. We saw how to exploit the `and_then()` function to do it. But in the previous part we cheated using the `Box<Error>` trait as error type. Why haven't I used a more specific error type? It turns out when you chain futures you must return *always the same error type*.

> While chaining futures the error type must be the same.

Let's try and demonstrate this.

We have two types, called `ErrorA` and `ErrorB` (yes, I know, not terribly original). We will implement the [error::Error trait](https://doc.rust-lang.org/std/error/trait.Error.html) even though is not strictly necessary (but it's good practice IMHO). The `Error` trait requires [std::fmt::Display](https://doc.rust-lang.org/std/fmt/trait.Display.html) too so we're going to implement that trait as well.

```rust
#[derive(Debug, Default)]
pub struct ErrorA {}

impl fmt::Display for ErrorA {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ErrorA!")
    }
}

impl error::Error for ErrorA {
    fn description(&self) -> &str {
        "Description for ErrorA"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}
```

`ErrorB` is the same:

```rust
#[derive(Debug, Default)]
pub struct ErrorB {}

impl fmt::Display for ErrorB {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ErrorB!")
    }
}

impl error::Error for ErrorB {
    fn description(&self) -> &str {
        "Description for ErrorB"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}
```

I've kept the implementations simple to prove my point. Now let's use these structs in out futures. Remember, a future it's just a `Result<A,B>` returning function with a slight different syntax.

```rust
fn fut_error_a() -> impl Future<Item = (), Error = ErrorA> {
    err(ErrorA {})
}

fn fut_error_b() -> impl Future<Item = (), Error = ErrorB> {
    err(ErrorB {})
}
```

Now let's call them in our `main` function:

```rust
let retval = reactor.run(fut_error_a()).unwrap_err();
println!("fut_error_a == {:?}", retval);

let retval = reactor.run(fut_error_b()).unwrap_err();
println!("fut_error_b == {:?}", retval);
```

The result is, unsurprisingly:

```bash
fut_error_a == ErrorA
fut_error_b == ErrorB
```

So far so good. Now let's try to chain these futures:

```rust
let future = fut_error_a().and_then(|_| fut_error_b());
```

What we are doing here is to call the `fut_error_a` function and then call `fut_error_b` one. We do not care about the value returned by `fut_error_a` so we discard it with an underscore.
In more complex terms we want to chain a `impl Future<Item=(), Error=ErrorA>` with a `impl Future<Item=(), Error=ErrorB>`.

Let's try and compile it:

```output
Compiling tst_fut2 v0.1.0 (file:///home/MINDFLAVOR/mindflavor/src/rust/tst_future_2)
error[E0271]: type mismatch resolving `<impl futures::Future as futures::IntoFuture>::Error == errors::ErrorA`
   --> src/main.rs:166:32
    |
166 |     let future = fut_error_a().and_then(|_| fut_error_b());
    |                                ^^^^^^^^ expected struct `errors::ErrorB`, found struct `errors::ErrorA`
    |
    = note: expected type `errors::ErrorB`
               found type `errors::ErrorA`
```

The error is clear. We should have used a `ErrorB`. We supplied an `ErrorA` instead. In general terms:

> When chaining futures, the first function error type must be the same as the chained one.

That's exactly what rustc is telling us. The chained function return a `ErrorB` so the first function must return a `ErrorB` too. It does not (it returns a `ErrorA` instead) so the compilation fails.

How can we handle this problem? Fortunately there is a *chainable* method called `map_err` we can use. In our example we want to convert the `ErrorA` in `ErrorB` so we inject this function call between the two futures:

```rust
let future = fut_error_a()
    .map_err(|e| {
        println!("mapping {:?} into ErrorB", e);
        ErrorB::default()
    })
    .and_then(|_| fut_error_b());

let retval = reactor.run(future).unwrap_err();
println!("error chain == {:?}", retval);
```

If we compile now and run the sample this will be the output:

```output
mapping ErrorA into ErrorB
error chain == ErrorB
```

Let's push the example further. Suppose we want to chain `ErrorA`, then `ErrorB` and then `ErrorA` again. Something like:

```rust
let future = fut_error_a()
    .and_then(|_| fut_error_b())
    .and_then(|_| fut_error_a());
```

The rule clearly works on pairs. It does not account for the whole composition. So we have to map the error in `ErrorB` between `fut_error_a` and `fut_error_b` and then the other way around: map `ErrorA` between `fut_error_b` and `fut_error_a`. Hideous but working:

```rust
let future = fut_error_a()
    .map_err(|_| ErrorB::default())
    .and_then(|_| fut_error_b())
    .map_err(|_| ErrorA::default())
    .and_then(|_| fut_error_a());
```

### "From" to the rescue

One way to simplify the above code is to exploit the [std::convert::From](https://doc.rust-lang.org/std/convert/trait.From.html) trait. Basically with the From trait you can tell Rust how to convert one struct into another automagically. The trait consumes the original error which is fine in our implementation. Also the trait assumes the conversion does not fail. Lastly, we can only implement traits for structs we own - ie written by us - so this approach cannot always be used.

Let's implement `From<ErrorA> for ErrorB` and `FromInto<ErrorB> for ErrorA`:

```rust
impl From<ErrorB> for ErrorA {
    fn from(e: ErrorB) -> ErrorA {
        ErrorA::default()
    }
}

impl From<ErrorA> for ErrorB {
    fn from(e: ErrorA) -> ErrorB {
        ErrorB::default()
    }
}
```

Now the previous code can be simplified by just calling the `from_err()` function instead of `map_err()`. Rust will be smart enough to figure out which conversion to use on its own:

```rust
let future = fut_error_a()
   .from_err()
   .and_then(|_| fut_error_b())
   .from_err()
   .and_then(|_| fut_error_a());
```

The code is still intermingled with error conversion but the conversion code is no longer inline. This helps the readability of your code considerably.
The Future crate is clever: the `from_err` code will be called only in case of errors so there is no runtime penalty of using it.

## Lifetimes

Rust signature feature is the explicit lifetime annotation of references. Most of the time, however, Rust allows us to avoid to specify the lifetime using *lifetime elision*. Let's see it in action. We want to code a function that takes a string reference and return, if successful, the same string reference:

```rust
fn my_fn_ref<'a>(s: &'a str) -> Result<&'a str, Box<Error>> {
    Ok(s)
}
```

Notice the `<'a>` part. We are declaring a lifetime. Then with `s: &'a str` we are creating a parameter that will accept string references that must be valid for as long as `'a` is valid. With the `Result<&' str, Box<Error>>` we are telling Rust that our return value will contain a string reference. That string reference must be valid as long as `'a` is valid. In other words the passed string reference and the returned object must have the same lifetime.

That said this syntax is so verbose that Rust allows us to avoid specifying lifetimes in common case such as this. So we can rewrite the function this way:

```rust
fn my_fn_ref(s: &str) -> Result<&str, Box<Error>> {
    Ok(s)
}
```

Notice there is no longer a mention to lifetimes, even though they are there. This function declaration is much simpler to understand at glance.

But... you cannot elide lifetimes when working with futures (yet). If you try to convert this function to the same `impl Future` one as we did in the previous blog post:

```rust
fn my_fut_ref_implicit(s: &str) -> impl Future<Item = &str, Error = Box<Error>> {
    ok(s)
}
```

You will get an error. In my case (using `rustc 1.23.0-nightly (2be4cc040 2017-11-01)`) I've got a compiler panic:

```output
   Compiling tst_fut2 v0.1.0 (file:///home/MINDFLAVOR/mindflavor/src/rust/tst_future_2)
error: internal compiler error: /checkout/src/librustc_typeck/check/mod.rs:633: escaping regions in predicate Obligation(predicate=Binder(ProjectionPredicate(ProjectionTy { substs: Slice([_]), item_def_id: DefId { krate: CrateNum(15), index: DefIndex(0:330) => futures[59aa]::future[0]::Future[0]::Item[0] } }, &str)),depth=0)
  --> src/main.rs:39:36
   |
39 | fn my_fut_ref_implicit(s: &str) -> impl Future<Item = &str, Error = Box<Error>> {
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.23.0-nightly (2be4cc040 2017-11-01) running on x86_64-unknown-linux-gnu

thread 'rustc' panicked at 'Box<Any>', /checkout/src/librustc_errors/lib.rs:450:8
note: Run with `RUST_BACKTRACE=1` for a backtrace.
```

Don't fret on it, remember `impl Future` is still a nightly-only feature. To solve it we just have to **avoid** lifetime elision by explicitly annotating the references with lifetimes:

```rust
fn my_fut_ref<'a>(s: &'a str) -> impl Future<Item = &'a str, Error = Box<Error>> {
    ok(s)
}
```

This will work as expected.

### impl Future with lifetimes

The need to explicitly express the lifetimes goes beyond the parameters. If you return an `impl Future` constrained by a lifetime you have to annotate it as well. For example suppose we want to return a future String from a function taking a `&str` as parameter. We know we must annotate the parameter with lifetimes so we might try this:

```rust
fn my_fut_ref_chained<'a>(s: &'a str) -> impl Future<Item = String, Error = Box<Error>> {
    my_fut_ref(s).and_then(|s| ok(format!("received == {}", s)))
}
```

This will not work: the returned future is not constrained by `'a`. The error is:

```output
error[E0564]: only named lifetimes are allowed in `impl Trait`, but `` was found in the type `futures::AndThen<impl futures::Future, futures::FutureResult<std::string::String, std::boxed::Box<std::error::Error + 'static>>, [closure@src/main.rs:44:28: 44:64]>`
  --> src/main.rs:43:42
   |
43 | fn my_fut_ref_chained<'a>(s: &'a str) -> impl Future<Item = String, Error = Box<Error>> {
   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```

To solve the error all you have to do is to append `'a` to the `impl Future` declaration, like this:

```rust
fn my_fut_ref_chained<'a>(s: &'a str) -> impl Future<Item = String, Error = Box<Error>> + 'a {
    my_fut_ref(s).and_then(|s| ok(format!("received == {}", s)))
}
```

Credit goes to [HadrienG](https://users.rust-lang.org/u/hadrieng/summary) for this. See [Trouble with named lifetimes in chained futures](https://users.rust-lang.org/t/solved-trouble-with-named-lifetimes-in-chained-futures/11943).

Now you can call the function using your reactor as usual:

```rust
let retval = reactor
    .run(my_fut_ref_chained("str with lifetime"))
    .unwrap();
println!("my_fut_ref_chained == {}", retval);
```

And get the expected output:

```output
my_fut_ref_chained == received == str with lifetime
```

## Closing remarks

In the [next post](https://dev.to/mindflavor/rust-futures-an-uneducated-short-and-hopefully-not-boring-tutorial---part-3---the-reactor-433) we will cover the reactor. We will also write a future implementing struct from scratch.

-----

Happy Coding,
Francesco Cogno