Such an insane amount of work to avoid fixing the real problem: the inefficiency of threads.
All async code -- all of it -- is a hack to implement lightweight threads through a lot of syntactic sugar for state management. In a language like Rust it adds a ton of complexity that simply doesn't need to exist without it.
Fixing the efficiency and scaling issues of threads would make all of this just go away. Poof. Gone.
It's a bit like the trillion dollar mistake of "null" in languages like Java-- a ton of complexity that results from one design decision (or in this case lack thereof).
This.
The harmful decisions Rust made highlight its ingrained culture of doubling down on previous mistakes at all costs.
There seems to be no reevaluation of the cost/benefit ratio once the "preferred approach" turns out to be non-viable.
"We want to have feature X, consequences be damned" is rarely a winning move in language design.
Despicable comment and false.
Is it 'despicable' just because you don't like what it says? You didn't do anything to refute it.
I've written thousands of words on my blog about the design of async Rust, in which I carefully explain every decision and discuss the strong and weak points. This person regularly post rude low-effort comments like this one. My body of work should be enough to refute the idea that all I'm doing is doubling down. That a large part of Hacker News is fooled by cranks like simon-o does not surprise, but does speak poorly of this communities discernment.
Some Rust people just have to be that dramatic.
I think he's talking about OS threads... it has nothing to do with rust's decisions.
It has everything to do with Rust's decisions.
Talking about a "decision" only makes sense if there's a reasonable alternative.
Do you think "actually fixing" OS threads was a reasonable alternative? What would you prefer for a high performance abstraction instead of async?
I think there are some lessons that can be learned from Java's virtual thread approach – note that there is a huge gap in requirements and design trade-offs, especially around embedded, when compared to Rust.
I'd just wager that the effort of getting something like that into shape is smaller than the costs of async/await.
(And no, Rust's playing with green threads once 15 years ago and failing due to quality-of-implementation issues is not an excuse to dismiss everything that came after it off the bat.)
Though it's probably not worth discussing this whole topic with Rust fans currently:
Many made async/await part of their personality and have little experience to offer besides breathlessly pointing to one of the half dozen blog articles trying to defined async/await.
It will take a few years until that language feature runs through all stages of grief and one can have an adult discussion about it.
True but I didn't just mean Rust... I meant virtually all async coding as a pattern.
Agreed, it's just that in Rust async/await hurts more than in e. g. JavaScript where the browser gives you enough hooks to have a "fresh start with(out) async".
Marking the difference between a function that synchronizes with a concurrent process and a function that does not is good, actually.
If I could ask independently of the sentiment of this thread - I am genuinely curious: Why is marking the difference good? (sorry this is only tangential to the article)
Threads don't support cancellation in any reasonable way. Cancellation is immensely useful for networked applications and for GUIs.
Threads make it difficult to fully use CPU and network, without over-subscribing either one. If you start handing off tasks between threadpools, you're on the path to reimplementing futures (or you work on callbacks/events, which make the code fragmented, and which async/await was meant to be a syntax sugar for).
The alternative for cancellation and timeouts requires weaving a Context object like golang does, and then having issues with leaf code naively calling functions that don't obey the Context properly, which is only marginally better than pains with non-async functions in async code.
Everything you're describing goes back to problems with thread APIs. I agree that threads as implemented are very coarse grained and limited. What I dislike is the idea of inflicting an explosion of cognitive load onto the programmer to manually manage things instead of thinking about how to implement a better kind of thread.
The latter is what Go did. I'm not a giant Go fan but not having async is far and away the best thing about the language and makes up for almost all its other faults.
Anything the language makes the programmer think about detracts from the programmer's ability to think about the actual problem they are solving.
BTW Rust is still superior to C++ and I use it, so I am not dissing Rust too badly. The async cancer is found across the entire ecosystem, not just Rust, so my comment was more against async programming in general as opposed to getting threading right. If we could get threading right we would massively simplify all programming everywhere.
Ultimately it boils down to the fact that it's 2024 and we still run everything on 1970s operating systems.
I doubt rewriting the Linux kernel to "fix the efficiency and scaling issues of threads" is possible, but even if it is, the Rust experts who figured out how to get Pin to work are presumably not the same as the set of kernel experts who would be capable of doing so. So what do you think they should have done, concretely? Just thrown up their hands and said "well, we won't add async to our language, because in theory someday someone might fix Linux to make threads magically fast" ?
Unfortunately crossing the user space barrier would cost something regardless of how lightweight "threads" would be. Also, making the OS the scheduler for all async tasks would preclude different scheduler designs since every runtime would have to use the OS's scheduler.