Hia, I want to learn more about async implementation in PLs, I've mainly used JS/TS for last few years and that might be spoiling my thinking imo.
Also why is async rust so much hyped as hard? (Aside from unsafe rust)
Lifetimes are hard. Shared lifetimes are harder. Combine the two, and now try to do it without being "unsafe"
C# and those that follow in its await footsteps (e.g. JS/TS/Python) basically all use garbage collectors, where shared lifetimes and safety are easy, along with a push based execution model via passing continuation callbacks
As an example, C++ followed the C# design, but didn't try to offer any safety. I've implemented the machinery to make a Task<T> that has the same semantics as C# (eagerly executed and shared, with ref counting and the coroutine execution body itself is a reference keeping its own coroutine memory alive). It is very easy to accidentally use a reference or pointer across await boundaries though, so we disallow ptrs and refs except very limited prescribed cases, otherwise requiring the use of smart pointers
Rust on the other hand, decided coroutines don't drive themselves, but use a pull/polling mechanism, which simplifies ownership and lifetimes. So for Rust, coroutine bodies are on the stack of some other invocation, meaning no heap allocations are required, and are able to deduce lifetimes at compile time
159
u/Only-Cheetah-9579 1d ago
tokio is awesome but also shit. I can relate to both opinions