11 ms·
First it was "Rust's async isn't f#@king colored!" (https://www.hobofan.com/blog/2021-03-10-rust-async-colored/ https://www.hobofan.com/blog/2021-03-10-rust-asy
by diragon 5y ago
First it was "Rust's async isn't f#@king colored!" (https://www.hobofan.com/blog/2021-03-10-rust-async-colored/ https://www.hobofan.com/blog/2021-03-10-rust-async-colored/)
Then "Rust async is colored, and that’s not a big deal" https://morestina.net/blog/1686/rust-async-is-colored https://morestina.net/blog/1686/rust-async-is-colored
And now it's a good thing.
Honestly, this sounds like somebody struck Achilles' heel of Rust and it hurts. They're neatly covering 3 stages of grief over these 3 articles, and I wouldn't be surprised if we could uncover the other 2 in the blogosphere somewhere.
- skohan 5y agoI actually have found all the angst and consternation around the "coloring" of Rust's async approach to be rather funny, because there are heaps of concepts in Rust which introduce something analogous to function coloring. A good example would be lifetimes. Once you introduce lifetime parameters into a data type, it starts to introduce ballooning complexity into everything that touches it.
- orra 5y agoIs that problematic in practice? Write functions that are pure or take references (not ownership), and for the rest, use a judicious .copy()?
- skohan 5y agoYeah sure it's problematic. For instance, if you have a deeply nested struct, and you have to add a lifetime somewhere in the bottom, now you have to propagate it all the way up to the top level. Also if you run into a case where you need an explicit lifetime in a function somewhere, this ends up propagating outward. I've run into cases with Rust where I refactored a significant portion of a program to avoid nested references and explicit lifetimes in a way I haven't had to in other languages
- fauigerzigerk 5y agoYes, but you only have three choices basically: a) Accept the performance hit that comes with GC or defensive copying. b) Convince yourself that developers can keep all those potentially dangling references in their heads at all times. c) Use something like Rust lifetimes. My preference would be (a) whenever possible, (c) when absolutely necessary, and never (b)
- zozbot234 5y agoYou don't need GC or copying. Rust supports reference-counted handles that will never dangle, and will only leak in very rare cases involving self-referential data structures.
- fauigerzigerk 5y agoI consider reference counting a form of GC - a rather slow one with lots of potential pitfalls.
- nickez 5y agoIt might be slow, but it is deterministic which is more important in systems programs.
- Joker_vD 5y agoIn what sense it is deterministic? Any refcount decrement may or may not be the last one and that may or may not cause a huge graph of objects being free()d which (even without destructors) takes unpredictable amount of time. Then again, malloc() itself is usually not deterministic in a sense that it may take an arbitrary amount of time to make an allocation: many implementations shift work from free() to malloc() to get better asymptotic time complexity.
- pkolaczk 5y ago
- tadfisher 5y agoThese are three different opinions from three separate people. Please consider that the Rust community does not share one consciousness, as your post doesn't add anything useful to the conversation.
- wffurr 5y agoThe other links are interesting context for the debate over async in the Rust community. Too bad GPs post didn’t frame it that way.
- deleted 5y ago[deleted]
- darthrupert 5y agoIs that why 5 different people answered parent's comment dismissingly over a 15 minute period?
- lukebitts 5y agoSo are you arguing that the rust community shares one consciousness? Cause otherwise I don’t see your point
- deleted 5y ago[deleted]
- fshbbdssbbgdd 5y agoIf any community were equipped to navigate the challenges of sharing one consciousness, surely it would be Rust.
- mumblemumble 5y ago> They're neatly covering 3 stages of grief over these 3 articles No. It could only be something like three stages of grief if a single person were cycling among these positions. When it's just three different people writing three different blog posts, it's either three completely unrelated things, or a debate.
- pwdisswordfish8 5y agoOr maybe, and just maybe, the whole ‘stages of grief’ concept is not actually predictive of which opinion is actually right, and it’s just a cheap rhetorical trick providing an excuse to patronizingly dismiss someone else’s scepticism towards an idea.
- deleted 5y ago[deleted]
- adonovan 5y agoExactly. Kubler-Ross, the author of the original "stages of grief" paper, has since tried to clarify her horribly misunderstood idea: the "stages" are neither essential nor sequential, but are merely some of the many ways in which people react to grief.
- deleted 5y ago[deleted]
- ghosty141 5y agoI doubt the commentor was 100% serious when applying the "stages of grief" to blogposts.
- clarge1120 5y agoThank you. The Gamma radiation was starting to glow.
- mumblemumble 5y agoTrue, but whether or not something is a joke and whether or not it is rhetorically misleading are orthogonal characteristics.
- Sacho 5y agoThe two articles you list actually agree with each other - the second one is basically a more thorough argumentation of the points raised in the first one. For example, the first article agrees that "async is colored"(despite the title), but that the big issue of "colored" functions, "You can only call a red function from within another red function", doesn't exist in Rust. This is also a major point in the second article. I think a more accurate description would be that Rust async is informed by painful async implementations(Javascript) and has tried to avoid most of their shortcomings.
- pornel 5y agoThis is because the original article talked about a couple different things under the same title of a "coloring" problem: 1. JS has no way to wait for results of async functions in a sync context. This creates hard split between sync and async "colors". This is what most people agree is the major problem. 2. C# can avoid the split, but the syntax for using sync and async is different. The original article wasn't very clear about why this is bad, other than it exists. The second case gets interpreted as either: 2a. Programming languages should be able to generically abstract over sync/async syntax. 2b. Programming languages shouldn't have a different sync/async syntax in the first place. Rust's case is consistently: - It generally doesn't have the problem #1. Sync code can wait for async. Async code can spawn sync on a threadpool. There are some gotchas and boilerplate, but this kind of "color" isn't an unsolvable dead-end like it is in JS. - It has distinct syntax and execution model for async, which still counts as "color" (#2) per the original article. However, Rust can abstract over sync and async, so it doesn't have the problem #2a. The syntactical distinction is very intentional, so it doesn't consider #2b to be a problem at all.
- merb 5y agothe problem is that if you introduce async, your could should preferably async all the way to the bottom. of course you can trick yourself by using thread pools and move long running functions to them, but not everybody knows that. of course sync functions have the same problem (not the same problem, but it's the same concept, just in the other way), except that most frameworks just deal with it at the very front, so developers do not need to deal with it.
- pornel 5y agoThe whole point is that use of async doesn't need to be infectious. You may want to make everything async for elegance and consistency, but it's not a requirement strong enough to cause problems. If you have a library that is sync-only, it's fine. If you have a large project and can't be bothered to rewrite everything to be async, it's fine. "Not everybody knows (how to do) that" is a weak argument, because it's a relatively straightforward thing to learn: if it can block, wrap it in `spawn_blocking()`.
- jackcviers3 5y agoBut they are a good thing, from a type perspective, they encode the idea that a side-effect is going to happen at the type level, and then force you as the caller to handle that fact or pass the buck to your caller. Effect types are a signal for all programmers that "Here be dragons". They outline parts of your code which may not be safe to reorder during refactoring. And they can cover so much more than just asynchronous I/O. [1] 1. https://en.wikipedia.org/wiki/Effect_system https://en.wikipedia.org/wiki/Effect_system