Why do some types have Future trait but not others in tokio

This isn't a help request, but rather the result of figuring out the answer myself after hours of searching with no answer to this specific question. Maybe this can help people in the future (heh).

The Problem

So I am working my way through a little project and wanted to use async / tokio. So far a lot of stuff is working great, however I don't understand how await is working in some cases.

The most common example being listening TCP, I see no Future implementation

TcpListener accept method returns TcpStream type. I would expect to see a Future implementation listed in both of these pages, however there is none, yet I can still obviously use await and it works fine.

However, for Sleep, there it is, but it also works the same way.

It is even more odd that when I run these tests, I get unexpected results

use tokio::net::TcpListener;

fn main() -> () {
    TcpListener::bind("127.0.0.1:8080").hgfjk();
}
use tokio::net::TcpListener;

#[tokio::main]
async fn main() -> () {
    TcpListener::bind("127.0.0.1:8080").hgfjk();
}

Both give the same error

error[E0599]: no method named `hgfjk` found for opaque type `impl Future<Output = Result<tokio::net::TcpListener, std::io::Error>>` in the current scope
 --> src/lib.rs:5:41
  |
5 |     TcpListener::bind("127.0.0.1:8080").hgfjk();
  |                         

I also checked out async-std and mio, and many of their types also lack a Future implementation.

I know await isn't really a method, but how is it working exactly if there isn't Future for all types?

The Answer

Note the function signatures and the async keyword.

For TcpListener we have this method

pub async fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener>

The async keyword causes return type to be transformed as follows:

impl Future<Output = Result<tokio::net::TcpListener, std::io::Error>>

Why we could find Future trait for Sleep? Because Future was implemented for Sleep some reason I don't know and is beyond the scope of the document.

tokio::time::sleep is a function that returns a Sleep.

Here is the function signature. Note the lack of the async keyword.

pub fn sleep(duration: Duration) -> Sleep

Hope this helps someone in the future. If anyone has anything to add, feel free.

In case that isn't clear, sleep is not an async fn but an ordinary fn. The advantage that this gives is that you get more flexibility beyond just calling sleep(…).await. If you store the returned future, you can, before awaiting it, use other methods the struct offers. And - if done correctly - you can even reset and re-use such a Sleep future, even after awaiting it.


For the record, mio doesn't offer any futures at all. It's a rather low level crate that offers a way to group together a bunch of io actions in a registry that enables you to block for precisely as long as it takes until any of the registered operations finishes / has an event. This is the basic component that allows properly handling multiple io things in the same thread, the basic building block for "asynchronous" / "non-blocking" programs.

Tokio is implemented on top of mio and makes it easier to use by offering API as async fns / Futures, and providing the necessary infrastructure to run these futures and to execute their IO actions properly through mio.

Thanks for the reply.

That's good to know about Sleep and things that implement Future rather than return Future.

I actually didn't check mio much, but yeah, turns out at least in the net module I checked, the types don't implement Future nor are the functions/methods async. I didn't bother to go back and check after I thought I cracked the code.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.