When learning Rust a few months ago, I built a small client library for a REST API using reqwest (which uses Tokio). I then started writing a web app using Tide (https://github.com/http-rs/tide). I eventually realized that it would be difficult to use the library I had built earlier since Tide uses the async-std runtime rather than Tokio. That was very disappointing. Is there any plan to make it easier to write "runtime agnostic" libraries in the future?
Yes, that is what I alluded to at the end. There's a few points here that still need some interop work. The intention is to fix that, but it's non-trivial. We'll get there.
You can make libraries runtime agnostic, but it requires a bit of design to get right. We tried our best with Tiberius[0], so you just need to provide an object implementing the AsyncRead and AsyncWrite traits from the futures crate, such as the TcpStream from async-std or tokio (using their compat module).
It is not perfect yet, and especially how tokio does not follow the rest of the ecosystem by implementing their own traits is kind of disappointing. We can work around that, but I was hoping they would fix this by version 1.0...
Yup, building libraries on IO traits which then are implemented by the particular runtimes is a good way to have a runtime agnostic library. Ideally the IO traits are defined in the library itself, to make them not again dependent on another moving target. You can provide implementations of the "glue code" for particular runtimes in separate crates to ease integration for users.
Another way to be runtime agnostic is to start a particular runtime as part of your library, which is used internally. The public interface of your library can provide async functions which are agonstic to a particular runtime, since all actions will be deferred/forwarded to an internal runtime. That approach has a bit more overhead, but can ease usage.
I had the exact same experience. I think it can be a pretty big barrier to getting started, as you really have to lock into a sub-set of the ecosystem (i.e. I can only use crates that have support for Tokio).
I understand the reasoning for not wanting this in the core language, but perhaps there could be some standard implementations which would still allow for custom runtimes.
You can make async-std mimic a tokio runtime by adding “tokio02” or “tokio03” to the list of features for async_std. At its core, futures and future combinators work under all runtimes, it’s just some features will complain if they don’t detect the tokio runtime.
that's a good point, when playing a bit with rust last year I found that the libraries that deal with "async stuff" (like http clients, db clients etc) are mostly split, some use tokio and some use async-std, and they were incompatible. Not sure if the situation has improved now but it looked like an ecosystem split at the time.