3 ms·
The GAT complexity is due to async working without extra per-task allocations. If you allowed a heap allocation per each Future (like e.g. JS does for each Prom
by pornel 4y ago
The GAT complexity is due to async working without extra per-task allocations. If you allowed a heap allocation per each Future (like e.g. JS does for each Promise), it'd be pretty simple, but Rust goes to great lengths to avoid heap allocations.
Rust can merge the entire call tree of async execution (which can be as large as the whole program if async recursion isn't used) into one struct that represents entire state space needed from start to finish. This struct has a static type and a fixed size known at compile time. Describing that type in the type system, including all the generics and lifetimes, is pretty complex.
Pin is a bit of a technical debt. It has been invented to ship async/await without having to first add non-moveable/self-referential types to the language. It is more clever and clunky than a first-class language feature could be. OTOH async/await has been production-ready for a few years now, and non-moveable types are still not a thing, so the trade-off was worth it.
In practice you don't need to even know about Pin if you're just using async/await syntax. It's needed only for lower-level plumbing, like custom runtimes or clever low-level primitives that can't be expressed in normal async code.