3 ms·
> AsyncIterator and async generators For what it's worth, Dart has had synchronous and asynchronous generators (including `await for` statements) for as long a
by munificent 3y ago
> AsyncIterator and async generators
For what it's worth, Dart has had synchronous and asynchronous generators (including `await for` statements) for as long as its had async/await. They are neat features. I've definitely written code using synchronous generators that would be hard to manually transform into a custom Iterable implementation.
But they add a large amount of complexity to the language implementations and it turns out are very rarely used in practice. Here's a quick scrape I did of the most recently published 2,000 packages on our package manager:
-- Style (64317 total) --
59409 ( 92.369%): normal =================================================
4842 ( 7.528%): async ====
42 ( 0.065%): async* =
24 ( 0.037%): sync* =
Async/await is clearly pretty useful with there being one for roughly every ten normal functions. But generators and async generators are barely used at all.
Rust might be a in a different situation because efficient concurrency may be much more important in a systems language, but it's not clear to me that those same features carry their weight in Dart.
- vorticalbox 3y agoI've just used an async generator when upgrading to aws-sdk v3, the function lists all the items in a s3 bucket, if its truncated then it yeilds a recursive generator. Stops when it's got all the keys. First time in 5 years writing typescript I've actually used a generator.
- MajimasEyepatch 3y agoGenerators are one of those things that pop up more often in library code than in application code, I've found.
- no_wizard 3y agoGenerators (either variety) in JavaScript are flawed in their implementation in that they only went halfway with it. They also needed to make all primitive objects iterable as well, and/or they should have introduced iterable helpers for all data structures. The fact that you can't use an object in a `for` loop without implementing Symbol method(s) is a glaring hole in their every day utility. It makes it non-obvious to reach for in many cases The other to me is some of the semantics of generators are not well thought out, for instance, you have to call `.next()` _twice_ in order to get the first `yield` value, and how arguments to `.next()` should be used correctly is opaque. This combined with the fact `yield` doesn't follow the same lexcial scope as `this` does (IE, you can't have an arrow function yield if it was enclosed by a generator, unlike `this` which can be used inside an arrow function as reference to its enclosing scope. This would make generators far more useful IMO). Combine all this with the fact that most frameworks don't support generators natively for things like components (but they are starting to accept Promises / async functions) you end up with a relatively niche feature
- capableweb 3y agoI'm not sure "percentage of usage" is a metric you can use to fully decide how "useful" something is. Take macros in Clojure for example, usually you just have a few of those, but the ones you have are really useful, they give a lot of functionality and practicality to the language. Maybe the same thing is happening with sync/async generators?
- insanitybit 3y agoMacros are a really good example. A world without the equivalent of `#[derive(Serialize, Deserialize)]` would suck, but it's just a few characters and I almost never write macros personally.
- munificent 3y agoThat's a good observation about a lot of language features, yes. Macros are a particularly good example. But for a feature like generators which is, I think, essentially user-facing syntactic sugar, I do think a count of usages is a pretty good measure of usefulness. It's probably also worth noting that my data here is from published packages, which tends to skew towards reusable libraries and away from application code. So, if anything, I would expect this to be an over-count of their use if they primarily made libraries/frameworks useful on behalf of application developers.
- steveklabnik 3y ago> I think, essentially user-facing syntactic sugar, One thing to remember is that Rust is a bit weird here; often times, features like this are "sugar" in a sense, but that sugar lets you write safe code, whereas the non-sugar version would force you to write unsafe. This means this kind of thing is a larger win in Rust than it would be in other languages.
- munificent 3y agoYeah, that's a good point.
- withoutboats3 3y agoA big difference between Rust and other languages like Dart is that our async/await is based on the same sort of coroutine transform as generators would be, rather than continuations, so its a lot less additional complexity to add generators compared to another language that has both async/await based on continuations and generators based on coroutines.
- brabel 3y agoFor what it's worth: thanks to Dart's async/await and async* and sync* , I find it incredibly easy to write performant, clean concurrent code in Dart. I've implemented an application (very IO heavy, highly concurrent) that is half Dart, half Java (for reasons) and the async code in Java is atrocious, while the Dart code is just beautiful.
- ryansouza 3y agoI do wish discussions like the linked blog were more clear on specific use cases features would enable. Async summation shows off the syntax sure, but I don’t know any real world problems that are currently hard that this would make easy. Not to say there aren’t, just I don’t know them and would love to understand!