Also, this has all the goodness: open-source, high quality engineering, design in open, large contributors to a complex piece of software. Truly inspiring!
Also, this has all the goodness: open-source, high quality engineering, design in open, large contributors to a complex piece of software. Truly inspiring!
This is a foundational implementation and while you _can_ use it, you are also likely to run into a host of partially implemented support problems. No fault of anyone, just a lot left to do. Examples being, you may run into needing async FS ops, so you bring in one of those libs. You may need async traits, so you bring in macro helper libs, you may need async DB interaction, so you check your db lib and hope they have support. Etcetcetc.
None of those are problems to stop you from using Async if you want. They're merely reasons you may not want to use Async quite yet.
Personally I've found Rust's development cycle to be such a joy, including manual threading, that I can get by happily without Async for the time being.
But, I'm not currently doing a lot of work where I'm dying to use greenthreads-like paradigms. Threading works fine in my web frameworks, db pooling, parallel libs like Rayon, etc. So because I've got all the power in Rust I need currently I just have no reason to use Async.
WITH THAT SAID.. use it if you want it! I just might not recommend it to people coming into Rust unless they explicitly need Async. It's bound to introduce a few - hopefully mild - headaches, currently.
Traits are a big one for me. Though, I've seen good things with the Async Trait Macro libraries. So hopefully those do good.
It doesn't make this Async-Stable event any less big of course, not trying to downplay it. We can't really move forward without this, so I'm super happy to see it merged! I'm just hoping to manage expectations :)
1) this is an MVP, some features like you mentioned are not yet implemented
2) the echosystem was preparing for this release but it will likely have a bit of churn until things settle down now that the feature is in stable
3) there was a lot of diagnostics work to make the feature minimally understandable when something is incorrect, but it will be a source of frustration because it's not as polished as other constructs that have had the benefit of several releases and us seeing how they were misused to have targeted errors. Some things are already tackled in the new beta, but I foresee a lot of work ahead of us.
There are crates that provide ready-made ones, and that will work for almost all cases, but it's another dependency that you have to evaluate and stay on top of.
It is entirely possible to do yourself, though. Last month, I dove into the details during a game jam. Not much of a game came out, but I did manage to get a useful async system up and running from scratch:
https://github.com/e2-71828/ld45/blob/master/doc.pdf (cf. Chapter 3)
On a semi-related note, any thoughts on how you could merge Async with non-Async code? Eg, I've got a large codebase that is not threaded but not Async. In the future, I might upgrade the web server to be Async and slowly start porting code.
I had planned/hoped that I could make my own Async/Thread bridge. Such that non-Async code would live in it's own thread, and I would make a special Future ask a Mutex in another thread if data is available. Taking special care not to lock the Future's thread.
The goal of course is to not have to rewrite the entire app's blocking code at once.
Does this sound stupid to you?
There's an implementation in the standard library: https://doc.rust-lang.org/std/sync/mpsc/
Or a faster/more ergonomic one in the crossbeam-channel library: https://docs.rs/crossbeam-channel/0.4.0/crossbeam_channel/
You could of course have a channel that you simply use in a non-blocking fashion, asking if data is ready. You could also implement similar behavior in a Mutex.
However, I do think you're right, a channel would likely fit this paradigm better; and with less chance of accidentally blocking the executor/future thread. Appreciate the feedback, thanks!
The way I split up the game code, raw event handling and rendering was written as a standard, synchronous, game loop. The game logic update was written with async code, and once per frame, I call the executor which keeps control until none of the async tasks can make further progress.
You can probably do something similar in your case: find somewhere in the existing program where it isn't disruptive to do arbitrary work, and have the executor do its work there.
In general, Rust just has all the little details right. It's hard to describe that in concrete terms, but it makes using it a very smooth and satisfying process. I get a similar feeling when using postgres: there's usually a nice way of doing what I want, and I rarely come up against unwelcome surprises.
But I’m always curious about how it stacks up against other languages I’m less familiar with that share similar ideas.
Rust is great because it's low level, high-performance, non-garbage collected and it's primary inspiration for higher-level programming is languages like ML and Haskell.
I came from Haskell to Rust and it really is a joy to program in.
The ownership system is also a very clever approach to managing mutable state. Usually in F# you'd get something of the same effect by using immutable structures and creating new copies, which does have a small performance impact
Rust is the first language that is both truly good as a low-level systems language and also truly good as a high-level modern labguage at the same time.
To me, it's amazing to finally have another option aside from just C/C++.
Technically, I might have had some other options before, but rust gets it right.
I looked specifically at Ada, and for my use case macros are quite important. If I were to use Ada, I would need a separate code gen step.
I also need concurrency without making new threads. I know Ada can do async but it doesn't have something like tokio.
A shame. I wanted to give Ada a try, but didn't get very far before losing hope.