Hacker News new | ask | show | jobs
by Matthias247 2498 days ago
ValueTask is more of an optimization for scenarios where the Future (or Task<T>) is often intended to be ready immediately (synchronously). For those cases its wasteful to first allocate a continuation on the heap, and then not to use it - because the code after the await can directly be executed.

The introduction of ValueTask allowed C# code to only perform dynamic allocations whenever the task definitely needed to be yielded - opposed to one allocation for every Task<T>. However it doesn't allow for guaranteed avoidance of allocations - like Rusts model can do.

However on the positive side removing the allocations for those cases is probably good enough since the other yields are of low-frequency (when waiting for IO). And Rust code currently requires allocations like Box<dyn Future> in order to make certain things work (like type-erasure and dynamically dispatched interfaces) that are not necessarily required in .NET in the non-yielded case.

From an ergonomic perspective I definitely prefer .NETs easy-by-default model which is still highly optimizable up to the point of avoiding all allocations. But I understand why this wouldn't have worked for Rust and it's constraints (no GC, no classes, no runtime).

1 comments

Thanks for the thoughtful reply.

You are right, however there is a scenario that you have forgotten.

The possibility that the JIT might eventually optimise the code path given enough PGO data, and apply RVO or similar approaches.

Naturally I don't know if RyuJIT can already do this kind of optimization, given that only recently they have strengthened their focus on this area.

However this kind of optimizations are already doable in Graal, so it is possible that Microsoft also adds them to RyuJIT.

Which in any case would rule out some of the Rust deployment scenarios I guess.