Hacker News new | ask | show | jobs
by likeabbas 1369 days ago
It's very nice language and not just because of the language features. The tooling is awesome and modern. Compiler errors are top class, cargo is a great package manager, rust-analyzer is a great LSP.

However, I think the way the language has implemented `async` is going to cause a riff in the usage. Because they didn't standardize the executors interface, you're essentially forced to using a single runtime (Tokio) since library developers would have to code for each runtime. Also, because of the async keyword, library developers would also have to make a different sync/async of each function they want to declare.

These are not small issues and will only continue to get worse as people are forced to choose one route, leaving others to use a different language.

4 comments

> Also, because of the async keyword, library developers would also have to make a different sync/async of each function they want to declare.

No. If you are an async program calling a sync library, you can use `tokio::task::spawn_blocking`, and Tokio will run your sync function on a worker thread that's allowed to block https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.ht...

The `reqwest` library offers a sync API by just wrapping its own async API: https://docs.rs/reqwest/0.11.12/src/reqwest/blocking/client....

For libraries that don't do this convenience wrapping, you can just create an async runtime like `tokio::Runtime` and use a function like `block_on`: https://docs.rs/tokio/latest/tokio/runtime/struct.Runtime.ht...

Since all Rust programs have sync entrypoints, there is always some way to call async functions from sync functions. It's not like C# or Go where the async runtime is a singleton built deep into the language. You always have control of it.

In practice, if I'm doing anything with networking, I always end up wanting async, so I prefer to have the runtime and use spawn_blocking for sync APIs.

That's async calling sync. But if you're in sync and the only option is to call an async library because the author didn't want to make two versions then you have to pull in the async runtime as well.

Not everyone wants to pull in an async runtime just to run make a call to an API.

My whole point is async puts a huge burden on library authors that will force users to diverge in their approaches and that will ultimately hurt the community

Rust certainly wants to standardize the executors interface. People are working on it. See https://www.ncameron.org/blog/portable-and-interoperable-asy...
> The plan

> Kidding, I don't have a plan.

:|

> [B]ecause of the async keyword, library developers would also have to make a different sync/async of each function they want to declare.

This is a program with async in general, no? Go avoids this by just having everything be async, but that seems unsuitable for Rust since you won't have control over when your code executes and what thread it executes on, not a problem for applications but it would seem to rule out things like kernel modules and firmwares, as well as require every type to be Send + Sync (which ultimately means the language must be garbage collected).

In Python for example I've written async and sync versions of a library, and some magic testing that makes sure both implementations return the same results.

> These are not small issues and will only continue to get worse as people are forced to choose one route, leaving others to use a different language.

Honestly this doesn't seem like a problem to me. I think there's room for many languages in this world. Rust is a wonderful language but it isn't a "one true language." People should choose a different language if it suits them better. That's no more an indictment of Rust than it's an indictment of Python when I embed Rust in a web app - that's not a place where Python shines.

Sadly, I agree. It's a lot like C#'s quest against nullability: the feature was introduced too late into a stable design in a form that is obviously incomplete, tries too hard to maintain compatibility with existing code and fails.
I've never worked with C# so I need to look into that.

The one saving grace with Rust is if everyone decides to say "screw async" and just builds synchronous APIs, then we use something like [May](https://github.com/Xudong-Huang/may) for green threading.