4 ms·
Thanks, that's interesting point. I see how it might be useful, but it's still looks as a minor optimization that doesn't outweigh the drawbacks of the model.
by divan 7y ago
Thanks, that's interesting point. I see how it might be useful, but it's still looks as a minor optimization that doesn't outweigh the drawbacks of the model.
How do you deal with a situations when you have non-async/await code, and then you need to call just one function, which happened to be "async", and you can't do until you mark all your functions async as well? I find myself in this situation too often with Dart/Flutter, and it's especially embarrassing experience as it happens usually with a simple parts of code, where I don't need concurrency at all (like, get local directory name and store file to it). This "forced refactoring" also hits language design corners like "you can't call async functions" in constructor or `iniState()` and I end up writing async wrappers and other helpers functions just to make the whole thing work.
> it makes concurrency a _lot_ simpler
I find people put different meaning in the word "simpler". Do you mean that code requires less lines/chars to write or that it's easier to read and understand (those are totally different properties, often conflicting)?
- asark 7y agoI hate Node's model of async concurrency. I need one thing to happen, then another depending on the result of the first, and so on, way more often than I can let several things happen at once or in any order. Probably something like 100x as often. Even when I can have multiple pieces of logic executed at once or in any order, it's usually just a couple, and internally they usually comprise more of the same dependently-ordered execution. If I can really kick off a ton of something at once it's usually one function/operation, which again... consists, internally, of a bunch more stuff that needs to happen in a certain order. It'd be way more convenient if Node just assumed it couldn't carry on with the next operation until the current one was done, even if the current operation is async I/O—feel free to go off and process something else, just no more of my code—unless instructed otherwise. IOW, caller decides, yes. I 100% do not understand the appeal of a system where you have to specify that you do want the next instruction to wait on the result of the previous one. "But you'll block node's single thread during your I/O!" no, it can go do something else, just no more of this particular line of logic in my code unless I specifically tell it otherwise, thanks. Caller decides is both easier to follow and more useful.
- laughinghan 7y agoSounds like you might prefer Erlang or Go. But to be clear, "it'll block Node's single thread!" is not the reason for explicit await. The reason for explicit await is to guarantee that after calling a function foo(), only the state that foo() changes could have changed. Whereas after awaiting on an async function bar(), or any other promise, literally any state-mutating code in the entire application might have run. Obviously plenty of languages have this problem and deal with it, usually with locks like in Go and Java, or by banning shared mutable state entirely and only allowing message-passing for communication between concurrent "lines of logic" like in Erlang. (As far as I understand Go basically tries to get the best of both worlds by strongly encouraging message-passing, with locks intended only for advanced situations like custom concurrent data structures.) But there's no way for Node to change to either of those models without breaking every single nontrivial piece of code ever written in it. And apparently Rust intentionally chose not to go with those models because they require a runtime and make compatibility with C very difficult, well-known advantages over Go.
- staticassertion 7y agoI think this article justifies 'simpler' as more than just "characters to write". Rust is a fairly different language in that it isn't GC'd, and the async/await sugar really alleviates a lot of pain around that (among other things). As for calling async from sync, I imagine you just create a runtime and block on it.
- ClumsyPilot 7y agoIn C# you can't await an async in non-async function, but you can block until it's done. There is no drawback to having all code async.
- TravHatesMe 7y agoThere is a drawback: it pollutes the signatures of each asynchronous method and the signatures of the consumers. Each method now returns a Task, and each method name ought to have a suffix of 'Async'. It sucks that changing this will require all consumers to also modify their signatures as well. But I understand why it is necessary, the compiler needs to mark each 'step' in the asynchronous function to create a kind of state machine.
- Rusky 7y agoBut it doesn't pollute the signatures of the consumers, that's the whole point of this subthread. If you don't want/need to expose your async-ness, you just synchronously block on your async callees instead of awaiting them.
- bryanlarsen 7y ago> How do you deal with a situations when you have non-async/await code, and then you need to call just one function, which happened to be "async", and you can't do until you mark all your functions async as well? Just call the poll function on your Future. Just because Javascript sucks doesn't mean the similar feature in Rust does too. :)
- Tuna-Fish 7y ago> How do you deal with a situations when you have non-async/await code, and then you need to call just one function, which happened to be "async" This depends on what do you want to happen. Do you want to block on the one async function, or do you want to turn your current function into async and propagate the asyncness to your caller? Both options are available to you in Rust.
- ummonk 7y agoI think the people criticizing it are, like me, coming from other languages where blocking on async doesn't make your function sync. The asyncness still ends up propagating to the caller function in such languages.
- Tuna-Fish 7y agoThank you for putting it explicitly, everything here suddenly makes so much more sense. But yes, in Rust async is not a plague that irredeemably taints everything. You can choose to use anything that is async synchronously if you choose to, just by calling .poll() on the future at the callsite.