3 ms·
The important distinction of stackless coroutines-as-async vs. green threads-as-async is the function coloring problem. I think stackful coroutines are largely
by vacuity 3y ago
The important distinction of stackless coroutines-as-async vs. green threads-as-async is the function coloring problem. I think stackful coroutines are largely obviated given more manageable function coloring, structured concurrency, and whatnot that Rust is currently exploring and working on. Actual OS thread-like preemption probably requires a heavy runtime (I imagine Java can do this for their virtual threads?) or OS support, though. (See scheduler activations for the latter. They might actually catch on this time, who knows?)
- littlestymaar 3y agoI don't think “function coloring” (which is a concept that I find overhyped and uninformative anyway, especially when talking about Rust[1]) has anything to do with the difference between stackful and stackless coroutines: it's about whether you let the language insert yield points automatically or force the programmer to spell them out explicitly. We could make the exact same thing for blocking code by the way: just create two keywords `blocking`/`block` and mark all stdlib function that do trigger a blocking syscall as `blocking` and force the programmer to use the `block` keyword and transitively annotate the calling function as `blocking` and tada! You have static enforcement of blocking code (aka function coloring) in your language without even having any kind of coroutines. It also doesn't have much to do with structured concurrency either, and we could have gotten structured concurrency for free in Rust had tokio decided to cancel tasks handles on drop like futures are. And they even weren't that far of doing so[2] [1]: https://news.ycombinator.com/item?id=36497399 https://news.ycombinator.com/item?id=36497399 [2]: https://github.com/tokio-rs/tokio/issues/1830 https://github.com/tokio-rs/tokio/issues/1830
- assbuttbuttass 3y agofunction coloring is exactly the stackful/stackless division. Stackless functions can't be called from a stackful function without special ceremony
- littlestymaar 3y agoThis “ceremony” as you call it can totally be handled by the compiler, the same way the compiler deals with the unwinding ceremony without you ever knowing about it. The only reason why we ask the programmer to do it by themselves, is because explicitness is favored. This is exactly the same reasoning as the difference between Rust's `Result` and C++ exceptions. They serve the same purpose, they spread into the code base the same way (if on of the function you transitively call can raise an exception, you can raise an exception) but in one case we ask the programmer to to the bookkeeping manually so that it's explicit when reading the code. The only meaningful difference between stackful and stackless coroutines is the ability to write recursive function call. If your coroutines are stackless you need to box to avoid the sizedness issue, but in practice it's only marginally different from segmented stacks. If you have a moving GC and can just relocate the stack then you performance in case of recursive function call will be better, but it's also true about boxing if you have a generational collector with bump allocation. So this is mostly a difference of GC vs no-GC, in a situation where GC is actually improving performance characteristics.
- vacuity 3y agoI get where you're coming from, but it's a real problem that we have const-async-fallible-panicking-allocating combinatorial explosion. An effects system could abstract all of this away except for the base libraries and the application developers. A big goal of Rust is to be accessible, and all these sorts of "function colors" are a hindrance to that goal. > You have static enforcement of blocking code (aka function coloring) in your language without even having any kind of coroutines. And now it's annoying to write sync and async Rust.
- littlestymaar 3y ago> it's a real problem that we have const-async-fallible-panicking-allocating combinatorial explosion. True, but there's no free lunch: you either have the ability to express these things in the type system, or you don't. I'm personally very happy rust has `Result` even though it's legitimately much more tedious than having invisible exceptions. > A big goal of Rust is to be accessible, and all these sorts of "function colors" are a hindrance to that goal. It's always a trade-off between usability and expressive power. And not every Rust user have the same priorities. As an application developer, I care less about having allocations expressed in a tractable way than a kernel developer for instance. > An effects system could abstract all of this away Maybe, but it's not clear yet if that's something that could be added at this point. Also it would add yet another layer of complexity which is also a factor that needs to be taken into accounts. > And now it's annoying to write sync and async Rust. Honestly, this is just a matter of tooling: the annotation could/should be transitively added to every caller function (with a boundary at threads spawn) by something like `cargo fix`.