Live data from Hacker News

Why asynchronous Rust doesn't work

theta.eu.org

341–350 of 499 posts

Re: Why asynchronous Rust doesn't work

#341
post #256

> The thing I really want to try and get across here is that *Rust is not a language where first-class functions are ergonomic.* So... don’t use first-class functions so much? It’s a systems language, not a functional language for describing algorithms in CS whitepapers. Or use `move` (the article does mention this). There are easy paths in most programming languages, and harder paths. Rust is no exception. The fact…

> It’s a systems language, not a functional language for describing algorithms in CS whitepapers. This kind of toxicity is why I left programming behind as a career.

How is saying Rust is one thing but not another thing toxic? I never said it’s the author’s fault Rust is broken or anything like that. It just has some goals, and being a functional programming language isn’t one of them (as far as I know).

Re: Why asynchronous Rust doesn't work

#342
post #288

Earlier quoted context omitted.

"Ergonomic" is such a nebulous word as to be nearly useless honestly. I don't see how it is [unduly] inefficient or uncomfortable for a language at Rust's level to ensure that the programmer actually thinks through the execution of the code they are writing. If one doesn't want to think about such things - and there's absolutely nothing wrong with that! - there are plenty of higher level languages that can do that le…

I actually find ergonomic to be a very clear and intuitive term as it refers to programming language design decisions. And to use your cake analogy, the fact that a process is complex or laborious is orthogonal to the degree to which it is ergonomic. You could imagine baking a cake in a well organized kitchen with well designed, comfortable tools, or you could imagine having to stand on your toes and reach to the bac…

> I think this is a better analogy for ergonomics in programming languages.

While it may be a better analogy, it doesn't really reflect the way the term is used. In my (admittedly anecdotal) experience, most people's complaints about ergonomics are more of expecting difficult things to be easier than they inherently are than of the actual quality of the tools they are presented with. People think they are complaining about a mixer with too many settings, when in reality what they are complaining about is the fact that there are several variables that go into mixing batter and dough. They buy a mixer that's targeted at a baker or chef who wants complete control over how their batter comes out or who even needs a mixer versatile enough to also mill grain or roll pasta, then are predictably lost because it's not as immediately intuitive to use as a simple hand mixer. I don't think that makes the mixer not ergonomic, I think it just makes it not the right tool for that particular person.

Re: Why asynchronous Rust doesn't work

#343
I'd say the entire opposite of this author, async rust works well, it solves 99% of the problems I want it to solve in a practical and useful way, right now. And even better the resulting program is faster than anything I could have cooked up on my own.

Probably the only true comparable might be the scylladb seastar framework. And it's just that, with all the burdens that come with C++ coding. You won't find every client and server protocol under the sun implemented with it either which arguable async rust is building towards.

Re: Why asynchronous Rust doesn't work

#344
post #214
post #132

This is pretty overblown. I write async rust every day for my job, just fine, with no real problems. Probably because I'm consuming other libraries, I'm not trying to write my own. I use well-tested libraries like Actix-Web or occasionally Tokio. I've migrated multiple projects from futures to async/await once the syntax came out. ' The problems the author is describing might apply more to library authors, but for th…

> The problems the author is describing might apply more to library authors I don't know much about Rust, but I found the examples in the article kind of simple . As far as I can see, the author is trying to spawn a new thread and share an object between the main thread and the new one. It's seems like an everyday paradigm. Perhaps the problems arise when passing complex objects instead of native types (i.e. u32).

My job isn't to write a program that shares objects between threads. My job is to write a program that responds to web requests or stores user data or responds to queries or checks the state of certain services.

In some languages and frameworks, I might need to share an object between threads to do this efficiently. In Rust there are other options, e.g. using Arc or a reference or moving the object into a task. In my years of programming Rust I've never wanted to share some object on a thread, because there are frameworks and libraries (Actix-Web, Tokio, Rayon, async-std, others) that give me a higher-level abstraction for doing this.

I can understand using this as a point of comparison if you're not very familiar with the language. But I have to confess that in my three years of working with Rust, I've neer had to worry about threads. I've been able to use a library to solve my concurrency or parallelism problems so that I can go back to worrying about design or reliability concerns.

This won't be everyone's perspective, after all, someone has to write those libraries. But it is mine, and I think users of such libraries far outnumber authors of such libraries.

Re: Why asynchronous Rust doesn't work

#345
post #59

Earlier quoted context omitted.

I am guessing you are a point D/D' in the diagram [1] Although the diagram is for the Rust overall, I think something similar is true for async Rust. All I would say is hang in there. It gets better (from my experience). Rust is not something you can code along as you think. There is a bit a of upfront thinking what the data-structures & data-flow look like. At present, I can know in advance without writing code whet…

> Rust is not something you can code along as you think. This is my biggest gripe with Rust. I want to write code that produces the right result first and make it safe later.

We already have too much code that "can be made safe later", but never is.

Re: Why asynchronous Rust doesn't work

#346
post #18

For a few months while I was between jobs, I decided to learn Rust. Because async code is supposed to be better than threaded code, I spent all my time trying to write async Rust. Big mistake! I never accomplished what I set out to accomplish. Most of my experience is in C#, where the difference between async and threaded code is mostly syntax sugar. (Until you get into the details.) (And async code makes writing UI…

I sympathize. As I said in another comment, the issue isn't really caused by async, IMO. It's caused by the complicated and leaky abstraction of traits. I'd be willing to bet that your difficulties were more around dealing with the interactions of async + traits than if you had just written a bunch of async functions and then ran them inside an async main (via tokio's tokio::main attribute).

Just a guess.

Re: Why asynchronous Rust doesn't work

#347

Earlier quoted context omitted.

Thank you for the link! But immideately we can see the false equivalence: completion based API does not imply the callback-based approach. The article critigues the latter, but not the former. Earlier in this thread I've described how I see a completion-based model built on top of FSMs generated by compiler from async fns. In other words, the arguments presented in that article do not apply to this discussion. >The p…

> Earlier in this thread I've described how I see a completion-based model built on top of FSMs generated by compiler from async fns. In other words, the arguments presented in that article do not apply to this discussion. I've been lurking your responses, but now I'm confused. If you are not using a callback based approach, then what are you using? Rust's FSM approach is predicated on polling; In other words if you…

I meant the callback based approach described in the article, for example take this line from it:

>Unfortunately, this approach nevertheless forces allocation at almost every point of future composition, and often imposes dynamic dispatch, despite our best efforts to avoid such overhead.

It clearly does not apply to the model which I've described earlier.

Of course, the described FSM state transition functions can be rightfully called callbacks, which adds a certain amount of confusion.

I can agree with the argument that a proper async Drop can not be implemented in Rust 1.0, so we have to settle with a compromise solution. Same with proper self-referential structs vs Pin. But I would like to see this argument to be explicitly stated with sufficient backing of the impossibility statements.

Re: Why asynchronous Rust doesn't work

#348

Earlier quoted context omitted.

https://aturon.github.io/blog/2016/09/07/futures-design/ The completion based futures that Alex started with were also based on epoll. The performance issues it presented had nothing to do any sort of impedence mismatch between a completion based future and epoll, because there is no impedence issue. You are confused.

Thank you for the link! But immideately we can see the false equivalence: completion based API does not imply the callback-based approach. The article critigues the latter, but not the former. Earlier in this thread I've described how I see a completion-based model built on top of FSMs generated by compiler from async fns. In other words, the arguments presented in that article do not apply to this discussion. >The p…

> Please, tone down your replies.

You cannot literally make extremely inflammatory comments about people's work, and accuse them of all sorts of things, and then get upset when they are mad about it. You've made a bunch of very serious accusations on multiple people's hard work, with no evidence, and with arguments that are shaky at best, on one of the largest and most influential forums in the world.

I mean, you can get mad about it, but I don't think it's right.

Re: Why asynchronous Rust doesn't work

#349

Earlier quoted context omitted.

Are we talking about the same example? struct Database { data: Vec } impl Database { fn store(&mut self, data: i32) { self.data.push(data); } } fn main() { let mut db = Database { data: vec![] }; do_work_and_then(|meaning_of_life| { println!("oh man, I found it: {}", meaning_of_life); db.store(meaning_of_life); }); // I'd read from `db` here if I really were making a web server. // But that's beside the point, so I'm…

The `do_work_and_then` function does spawn a thread, it's one of the first things established in the article.

Ah, I thought it just named a block, my mistake.

Re: Why asynchronous Rust doesn't work

#350

Earlier quoted context omitted.

Definitely dynamic dispatch + async brings out a lot of pain points. But I only agree that the async part of that is unfortunate. Making dynamic dispatch have a little extra friction is a feature, not a bug, so to speak. Rust's raison d'être is "zero cost abstraction" and to be a systems language that should be viable in the same spaces as C++. Heap allocating needs to be explicit, just like in C and C++. But, I agre…

Oh yeah, I can totally relate to the Send-Sync-Unpin massaging, plus 'static bound for me. It's so weird that individually each of them kinda makes sense, but often you need to combine then and all of a sudden the understanding of combinations just does not.. combine. After a minute or two of trying to figure out what should actually go into that bound I give up, remove all of them and start adding them back one by o…

Yep. Same. I've been doing Rust for years at this point (not full time, and with long gaps- granted), and it's exactly like you said: individually these things are simple, but then you're trying to figure out where you accidentally let a reference cross an await boundary that killed your automatic Unpin that you didn't realize you needed. Suddenly it feels like you don't understand it like you thought you did.

The static lifetime bound is annoying, too! I guess it crops up if you take a future and compose it with another one? Both future implementations have to be static types to guarantee they live long enough once passed into the new future.

Post reply on HN