Rust that uses standard techniques for asynchronous code, or is synchronous, does not. Async/await sucks all the oxygen from asynchronous Rust
Async/await Rust is a different language, probably more popular, and worth pursuing (for somebody, not me) it already has a runtime and the dreadful hacks like (pin)[https://doc.rust-lang.org/std/pin/index.html] that are due to the lack of a garbage collector
Hi -- I'm the one who presented the talk -- honored!
I'm curious how you got to "async Rust needs a [tracing] garbage collector" in particular. While it's true that a lot of the issues here are downstream of futures being passive (which in turn is downstream of wanting async to work on embedded), I'm not sure active futures need a tracing GC. Seems to me like Arc or even a borrow-based approach would work, as long as you can guarantee that the future is dropped before the scope exits (which admittedly isn't possible in safe Rust today [0]).
The difficulties with async/await seem to me to be with the fact that code execution starts and stops using "mysterious magic", and it is very hard for the compiler to know what is in, and what is out, of scope.
I am by no means an expert on async/await, but I have programmed asynchronously for decades. I tried using async/await in Rust, Typescript and Dart. In Typescript and Dart I just forget about memory and I pretend I am programming synchronously. Managed memory, runtimes, money in the bank, who is complaining? Not me.
\digression{start}
This is where the first problem I had with async/await cropped up. I do not like things that are one thing, and pretend to be another - personally or professionally - and async/await is all about (it seems to me) making asynchronous programming look synchronous. Not only do I not get the point - why? is asynchronous programming hard? - but I find it offensive. That is a personal quibble and not one I expect many others to find convincing
I guess I am complaining....
\digression{end}
In Rust I swiftly found myself jumping through hoops, and having to add lots and lots of "magic incantations" none of which I needed in the other languages. It has been a while, and I have blotted out the details.
Having to keep a piece of memory in scope when the scope itself is not in my control made me dizzy. I have not gone back and used async/await but I have done a lot of asynchronous rust programming since, and I will be doing more.
My push for Rust to bifurcate and become two languages is because async/await has sucked up all the oxygen. Definitely from asynchronous Rust programming, but it has wrecked the culture generally. The first thing I do when I evaluate a new crate is to look for "tokio" in the dependencies - and two out of three times I find it. People are using async/await by default.
That is OK, for another language. But Rust, as it stands, is the wrong choice for most of those things. I am using it for real time audio processing and it is the right choice for that. But (e.g) for the IoT lighting controller [tapo](https://github.com/mihai-dinculescu/tapo) it really is not.
I am resigned to my Cassandra role here. People like your good self (much respect for your fascinating talk, much envy for your exciting job) are going to keep trying to make it work. I think it will fail. It is too hard to manage memory like Rust does with a borrow checker with a runtime that inserts and runs code outside the programmer's control. There is a conflict there, and a lot of water is going under the bridge and money down the drain before people agree with me and do what I say...
Either that or I will be proved wrong
Lastly I have to head off one of the most common, and disturbing, counter (non) arguments: I absolutely do not accept that "so many smart people are using it it must be OK". Many smart people do all sorts of crazy things. I am old enough to have done some really crazy things that I do not like to recall, and anyway, explain Windows - smart people doing stupid things if ever
Thank you for the kind words and the thoughtful response.
I'm deeply sympathetic to your viewpoint, and some days I certainly feel like Rust is creaking under its own weight. Why does your typical backend web service need all this complexity with borrows and lifetimes and manual memory management?
But allow me to present the other side of the argument. My background is in systems-level developer tools, and Rust has a combination of things that no other programming environment has:
* & and &mut, which enforce a rigorous separation between mutable and immutable state. I think this is the single most important feature of Rust, and the closest analog to this in other environments is purely functional languages like Haskell
* enums with data + exhaustive pattern matching; the latter is something even Haskell lacks
* high-level idiomatic code that performs like low-level code (e.g. iterators): Rust achieves this through an extraordinary combination of monomorphizing and inlining
* working in memory-constrained environments: tracing GC tends to have significant memory overhead, and I've worked in server environments where a big limiting factor was the amount of DRAM being produced globally
* fast startup times: this is a requirement for command-line tools people use hundreds of times a day—I spent many years working on Mercurial where Python's slow startup time was a very common complaint
* first-class support for using native OS calls directly; many higher-level languages like Java abstract away the details, so things like signal handling are hard to hook into
* first-class Windows support: again, non-negotiable for many developer tools, since the plurality of developers are on Windows
* and last but not least, a great dependency ecosystem, which ties into all of the above points: & and &mut mean that some transitive dependency three levels down won't suddenly alter the list you pass in, idiomatic performance means that perf regressions are rare, first-class Windows support means most dependencies just work on Windows, and so on
Is it possible to have an application-level/GCd/managed language that meets most or all of these requirements? Certainly. Does such an application-level language exist today? No, and there's nothing on the horizon either (Haskell has its heart in the right place, but is missing many of the more practical features here).
Rust isn't a great application-level language, but it's the best application-level language. And given how high the barrier tends to be for a new language to reach adoption, I'll probably be retired long before something like that shows up.
And yeah, async really is quite confusing in so many ways, and it's really unfortunate that this situation has seen no improvements in so many years. And yet, through its characteristics combined with the other things listed here, it enables developers to solve real problems that are completely infeasible in any other language.
I am unfamiliar but I think Go meets most of your requirements. Except of course: "working in memory-constrained environments: tracing GC tends to have significant memory overhead". Go has a garbage collector. The Go fans I know laugh in my face about my concerns with garbage collection resource use (especially GC pauses), very fast they say, very good. Mēh. Whatever, Go has been a success in the "developer tools" sector. AFAICT more successful than Rust
Does the embedded world need or want async/await? Is it worth paying the price of extreme complexity in many not so trivial use cases? Have many embedded developers asked for it? I expect not
My strong feeling is that async/await is making easy things easier and many common things harder. A managed runtime would improve the experience a lot - but it would not be the Rust we know. It would be mostly better.
I would not be interested. My interest in Rust is because I like control. I cannot make a business case for any use of Rust except in the places where C and C++ (my first loves) made sense, and that was (is) a very small sector in application programming.
> I am unfamiliar but I think Go meets most of your requirements.
Go definitely meets many of the requirements here such as fast startup time, but it (like every other imperative language that's not Rust) fails at the & and &mut separation which I've come to regard as the most fundamental requirement of all. Go also doesn't have enums with data and exhaustive pattern matching, and its Windows support is also a bit dodgy -- see things like https://pkg.go.dev/os#Chmod where they try to emulate Unix chmod on Windows. When writing Windows-specific code I want to use Windows idioms, not a Unix emulation layer.
> Does the embedded world need or want async/await?
Asyc/await really desperately needs a garbage collector. (See this talk from Rustconf 2025: https://youtu.be/zrv5Cy1R7r4?si=lfTGLdJOGw81bvpu and this blog:https://rfd.shared.oxide.computer/rfd/400)
Rust that uses standard techniques for asynchronous code, or is synchronous, does not. Async/await sucks all the oxygen from asynchronous Rust
Async/await Rust is a different language, probably more popular, and worth pursuing (for somebody, not me) it already has a runtime and the dreadful hacks like (pin)[https://doc.rust-lang.org/std/pin/index.html] that are due to the lack of a garbage collector
What a good idea