It doesn't really add anything new and flashy, but removes some annoying warts.
Sync code has scoped threads that enable multi-threaded execution within a function, without having to ensure the data outlives the function call. Async can't do that while guaranteeing safety. This makes tokio::spawn awkward and annoying, and is a major source why people dislike Rust's async.
Low-level async code that polls Futures requires using the Pin wrapper type, which is unergonomic, and doesn't really guarantee safety, but it's more like a "be careful here" sign. Proposed changes would make that code look more like normal Rust and work without unsafe escape hatches.
> and is a major source why people dislike Rust's async
It's worth mentioning that there is, in fact, no language out there other than Rust that can even do this in the first place.
Some languages give the illusion that they support it by boxing the stack frame of async functions and letting a garbage collector deal with the consequences, but that comes with significant drawbacks too (additional GC pressure, heap allocation overhead, requiring a GC in the first place).
You can do it with C++ coroutines, but it's much harder to do correctly than in Rust if you want to maintain any sense of conviction that the system is correct.
The main reason that structured async concurrency would be so awesome to have is that it feels like Rust has the right set of features that could enable it with a set of constraints that are so much more attractive than any other language out there can provide - no overhead, "just works" with no drawbacks.
(For the record, you can actually get pretty far today using primitives like `FuturesUnordered` instead of `tokio::spawn` and similar, but this sidesteps the runtime's scheduler, so YMMV. This basically creates a task-local mini-scheduler for your futures, which may or may not be sufficient.)
Skimming the proposal, that looks like the equivalent of the "executor" (scheduler) and "task" (sender) implemented in Rust async runtimes. I could have missed it, but I don't see anything in particular to help with managing structured concurrency?
Like, the central challenge is cancellation: In structured concurrency, subtasks spawned from a parent task must finish cancelling before the parent task can be cancelled.
>You can do it with C++ coroutines, but it's much harder to do correctly than in Rust if you want to maintain any sense of conviction that the system is correct.
C++ just lets you pass a reference or pointer from one task's stack to another task or thread, with no assurance that the callee task terminates before the caller's stack is deallocated (i.e. the caller returns before its children terminate).
This is a compile error in Rust, and you need unsafe code to achieve it. But then the real power is that you can construct a safe API that lets you do it safely, fully checked at compile time.
See `std::thread::scope` in the standard library, or `rayon::scope` if you want an implementation based on thread pools.
It doesn't really add anything new and flashy, but removes some annoying warts.
Sync code has scoped threads that enable multi-threaded execution within a function, without having to ensure the data outlives the function call. Async can't do that while guaranteeing safety. This makes tokio::spawn awkward and annoying, and is a major source why people dislike Rust's async.
Low-level async code that polls Futures requires using the Pin wrapper type, which is unergonomic, and doesn't really guarantee safety, but it's more like a "be careful here" sign. Proposed changes would make that code look more like normal Rust and work without unsafe escape hatches.