Async Rust, but less intimidating
Tags: rust, tutorial, async, futures
Published: 2020-07-16 01:50:20

For the last few years, Rust has been a fast-moving target. The language and supporting ecosystem are still evolving, meaning that even though the language is pretty stable overall, some details are still being figured out. 

One of those details has been support for asynchronous functions, which recently went stable in [version 1.39](https://blog.rust-lang.org/2019/11/07/Rust-1.39.0.html). However, a lot of what I've read while learning still uses older/non-standard implementations of async. It's also still pretty easy to come across code using pre-async/await futures, which were...[unpleasant](https://docs.rs/futures/0.1.29/futures/).

Separating the deprecated information from the current can be a little tricky at first -- I spent time learning a couple of APIs only to find out that they are already obsolete. It doesn't help either that Rust's Future-based approach to asynchronous code is, I suspect, a bit different from what many people are used to (coming from ECMAScript's `Promise` for example).

All of that, can make the task of writing asynchronous Rust code look a little bit intimidating.

**So!** In this post I'll give you a short guide to getting started with futures and async/await syntax in Rust 1.39+. We'll strip out all the cruft, and give you the up-to-date information that you need to get cooking. For you, it's only the latest and greatest from here on out. Lucky you!

## So, What's a Future?
In the broadest sense, a _future_ is an abstract object which represents a computation. Practically speaking, a future is a value which **tracks the state** of an asynchronous computation. Think of it as a placeholder for a value you will have sometime in the... **f u t u r e** 😎 ([get it? do you get it?](https://youtu.be/wM2LsKdUlx4?t=50)).

A future's "value" will either be _pending_, indicating that the computation is still running, or _ready_, indicating that the computation has returned a value. When ready, the _future_ object represents the value returned by the asynchronous call. Typically this value is wrapped in a `Result`, allowing you to handle error values the same as you would elsewhere in your Rust code.

If you have written any JavaScript recently, this concept will feel very similar to a _promise_.

**However!** There are a couple of key differences.

For one, Rust's futures are _lazy_. This means that they are not necessarily executed right away -- that is, just because you have _created_ a `Future`, does not mean you have _started_ a new computation. A future is technically started and executed by an _executor_ -- I'll explain executors further down, but in most cases you won't even need to know that you have one! 🙂

In comparison, JavaScript promises are _eager_. This means that they are always immediately queued for execution in the main event loop.

Another difference is that an executor may choose to run futures in parallel (via threads), whereas (to the best of my knowledge) JavaScript's event loop is single-threaded, meaning that promises are concurrent but not parallel.

![Squidward, on his back, repeatedly crunching his body and screaming the word "future"](https://dev-to-uploads.s3.amazonaws.com/i/734bbf0mtl81gg89dflb.gif)

## Basic Ingredients

As I hinted at earlier, async support in Rust is not entirely batteries-included. Rust leaves the async runtime out on purpose. There are many possible strategies for orchestrating asynchronous work, and in many cases the "best" strategy is application-specific. For example, [AssemblyLift](https://github.com/akkoro/assemblylift) uses both a standard tokio runtime, as well as the lightweight [direct-executor](https://crates.io/crates/direct-executor) to run futures inside the WebAssembly environment!

You will need some kind of _executor_; the executor is responsible for driving the future towards completion. Executors themselves typically require a few components of their own, which together make up a _runtime_. Fortunately, you don't have to write a runtime yourself! Even though Rust doesn't ship with a "standard" async runtime, there are many good choices available. I will be focusing on [tokio](https://docs.rs/crate/tokio/0.2.21), only because I've been following its development for a while so it's the one I'm most familiar with. The [async-std](https://docs.rs/async-std/1.6.2/async_std/#) crate seems popular, but I've never tried it personally.

## Practical Use

Let's look at a few concepts which I think are likely to be the most useful in your day-to-day. We'll start with the basics, and work our way to more advanced topics 🙂.

### Getting Started

If you don't need to deviate from the defaults (the standard, multi-threaded runtime), tokio makes it reaaaaal easy to get set up.

For example:
```rust
use tokio::prelude::*;

#[tokio::main]
async fn main() {
    println!("Hello, async world");
}
```

That's not much code, but it's doing **a lot** for you under the hood. The line `#[tokio::main]` is something called an _attribute macro_; here it's applied to `main`. At compile-time, the macro transforms your async function into all of the code **actually** required to set up a tokio runtime and spawn `main`.

In reality, the entry-point of a Rust program cannot be async -- a regular function first has to create a runtime, and then _spawn_ the first function on the runtime.

### Async Blocks

In addition to the `async fn foo()` syntax used for declaring asynchronous functions, Rust also provides something called an _async block_.

```rust
// you can also write `async move` if you need to move ownership
//    into the closure
tokio::spawn(async {
    an_async_function().await;
})
```

An async block is a [_block expression_](https://doc.rust-lang.org/reference/expressions/block-expr.html) which evaluates to a `Future`. If you aren't familiar with block expressions, don't worry! That level of detail isn't really necessary for using them, in my opinion. But there's also not that much to it! In Rust a _block_ is essentially any code surrounded by curly braces -- it's called an _expression_ because it *always* evaluates to a value (just look at a regular function definition -- that's a block expression!). In essence, they allow you to create an anonymous async function.

### Awaiting the Future

For any function that returns a `Future` trait object, Rust provides a convenient `.await` syntax.

For example:
```rust
use tokio::prelude::*;

async fn my_async_function() -> Result<u8, Error> { ... }

#[tokio::main]
async fn main() {
    let x: Result<u8, Error> = my_async_function().await;
}
```
Awaiting a future means that the current execution task will be *suspended*, until the `Future` being `await`ed returns a value (becomes _ready_). It's entirely possible (and likely) that the runtime will continue to run other futures in the background. 

The phrase "current execution task" is a little tricky. Originally, I thought this implied that the thread from which you called `await` would be blocked, however this isn't exactly true (credits for the correction at the bottom)! Under the hood, futures are executed in _tasks_ -- think of them like a container for your async code that provides context (context which you generally don't have see or interact with). The runtime can swap tasks within the same thread, so the thread isn't necessarily blocked while your future is `await`ing.

The `await` keyword can **only** be used inside a function declared `async`. It is also worth noting that even though `my_async_function` doesn't have an explicit return type, any `async` function **implicitly** returns a `Future` -- `async fn` is a shorthand provided by Rust to avoid having to include the full return type in the function declaration.

### Storing and Passing Async Functions

You may find yourself needing to store references to an asynchronous function, or passing one somewhere as an argument or attribute.

Storing an async function in a struct for example, requires you to use a _[trait object](https://doc.rust-lang.org/book/ch17-02-trait-objects.html)_.

For example:
```rust
use std::future::Future;
struct StructContainingAsyncFn {
    async_function: fn() -> dyn Future<Output=()>,
}
```

In the example above, we indicate that our `async_function` returns a Future trait object; this is the `dyn Future<Output=()>` type in the above example. This is the kind of syntax that the `async` keyword hides, in the places we can use it.

The "real" type of the Future is denoted by the `Output=()` type, which means that when the future resolves (ie, becomes _ready_) it will return a value of type `()`. If our asynchronous function was returning a `String`, we would write `dyn Future<Output=String>`.

Trait objects are also used when passing a future as an argument:
```rust
fn spawn_wrapper(future: impl Future<Output=()>) {
    // do something with the future here
    // you could combine it with other futures! 
    //    ^- we'll talk about this below 👇
    tokio::spawn(future)
}
```

The `impl Future` syntax is referred to as an [_impl trait_](https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/impl-trait-for-returning-complex-types-with-ease.html) (I pronounce it IMP-ull). Essentially this instructs the compiler that whatever is passed as the `future` argument *must* implement the `Future` trait.

### Combining Futures

Personally, this is one of my favourite (I spelled it correctly don't @ me) patterns with async Rust!

Up until now, everything I've shown can be done with the standard library. However, for combinators I'll be importing the [futures-util](futures-util = "0.3.5") crate which provides us the `TryFutureExt` trait. This trait provides additional methods for our futures, which we can use to combine asynchronous functions into *reusable* function chains.

```rust
use tokio::prelude::*;
use tokio::net::TcpListener;
use futures_util::future::TryFutureExt;

#[tokio::main]
async fn main() {
    let mut buf = [0; 1024];
    let mut listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
    listener
        .accept()
        .and_then(|(mut socket, _)| {
            async move {
               Ok(socket.read(&mut buf).await)
            }
        })
        .await;
}
```

This example is adapted from tokio's documentation. Here, instead of calling `listener.accept().await` and assigning an intermediate value (potentially doing some matching & error handling), we "attach" another function to it using `and_then`, which *only* runs the provided closure if the previous Future resolves successfully.

I found that at first, I really wanted to write something like:
```rust
and_then(async |...| {
    Ok(socket.read(...).await)
})
```

It feels (and looks) a little more natural, however async closures aren't stable yet (but I believe this kind of syntax can be enabled as an experimental feature).

Instead, `and_then` expects a closure which _returns_ a Future, for which I'm using an async block.

I called this pattern reusable, because we don't necessarily have to `await` the call chain where it's defined, as I have in the above example.

```rust
let my_complicated_call_chain: Future<...> = some_call()
    .and_then(|_| ...)
    .and_then(...);
```

Remember how earlier, I pointed out that Rust's futures are lazy? In the above code, nothing is actually being _invoked_ -- and it won't be, until the resulting Future is spawned either by `await`ing it, or spawning it directly.

I find a lot of operations I write require multiple async calls in succession, depending on whether/what the previous calls return to feed the next. This pattern is quite useful for combining these call chains and "freezing" them so that they can be reused. There are many more combinators besides `and_then`; I recommend reading the trait documentation for better detail than I can provide here.

## The Closer

That's all! However you landed here, I hope this was helpful, and that you got something out of it!

If you have any questions, want something explained more clearly, or want to point out a mistake I made -- write in the comments, or feel free to write me at xlem@akkoro.io!

#### Credits
<span>Cover photo by <a href="https://unsplash.com/@randomlies?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Ashim D’Silva</a> on <a href="https://unsplash.com/s/photos/road-fork?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span>

Update 2020/07/17: thanks to Reddit user `coderstephen` for [a couple of corrections](https://www.reddit.com/r/rust/comments/hsbs3o/async_rust_but_less_intimidating/fyam0m7?utm_source=share&utm_medium=web2x)!