5 ms·
This is my sentiment as well, I understand some people's reservations and the fact that "async pollutes every calling function, as now everything must async as
by marcus_cemes 4y ago
This is my sentiment as well, I understand some people's reservations and the fact that "async pollutes every calling function, as now everything must async as well", but to me this is correct behaviour and beneficial for the programmer. To me, this is akin to the pure/unpure function classification in FP, it makes sense that calling an unpure function would also "taint" the caller. Why should "fetch_user_db_which_may_be_on_the_other_side_of_the_world()" look the same as "Math.abs()", when their behaviour for the caller is so different?
I recently tried Go to speed up some Cloud Functions that use Firestore, it's very difficult to know which of the chained method calls of the Google-provided SDK is the one to actually "blocking" the green thread, perhaps they are all are unnecessarily? Without studying the source code, it's hard to know. I prefer explicitness over absolute simplicity. It also makes it easier to optimise code in my opinion as it's easier to identify sequential async calls that could actually happen concurrently, either by merging SQL queries or by using Promise.all() or the equivilent.
JavaScript does a good job with the await keyword in my opinion, you know exactly when something could take a significant delay, when it's doing something more behind the scenes. Rust does one better by making ".await" a suffix, allowing for nifty call chains. It communicates that this is an explicit yield point and could take a while.
- kaba0 4y agoBut with go's green threads, does it really matter if something blocks or not? Given, I'm not too familiar with Go, but in the case of Java's upcoming Loom which will do something similar, you would just create a virtual thread and if you have to do something with the output of a previous call, you just write plain easy "blocking" code. The JVM will switch to another virtual thread during the "blocking" part automagically and you are done. Whether something is async or not doesn't add anything to the idea you want to implement (in managed languages that is -- rust do need the async keyword because it is a low-level language).
- egeozcan 4y ago> But with go's green threads, does it really matter if something blocks or not? Then you keep pushing stuff to other threads "just to be sure", which may hurt performance but the worst part becomes reading that code.
- kaba0 4y agoThere is a fine balance here, I believe. Java plans on introducing something called structured concurrency to tackle this problem, but even without it I don’t believe that this is a unidirectional tradeoff. Async programming even with syntactic sugar can be overwhelming easily as well.
- Dylan16807 4y ago> To me, this is akin to the pure/unpure function classification in FP, it makes sense that calling an unpure function would also "taint" the caller. Well it also sucks if unpure code has to add a bunch of boilerplate annotations to every single function and call. > I recently tried Go to speed up some Cloud Functions that use Firestore, it's very difficult to know which of the chained method calls of the Google-provided SDK is the one to actually "blocking" the green thread, perhaps they are all are unnecessarily? If you have to mark enough of your functions as "possibly blocking" then you can get just as lost about which one is actually blocking in a particular situation.
- btschaegg 4y ago> To me, this is akin to the pure/unpure function classification in FP, it makes sense that calling an unpure function would also "taint" the caller. Since this could be read in a very abstract, purist way, I'd like to add that this is also very much an architecture concern for many pieces of code. At work, I regularly encounter issues with a piece of code that is written in one of the worst imaginable spaghetti styles. And, since it changes things in a database (not even in proper transactions, btw), and is written to pretty much prevent being tested, no one wants to touch it. Yet, what the code does would really match an "FP" approach: - Read in all inputs. You might even read during computation if you're simulating FP through transaction isolation - Compute the outputs and the new desired state - Pass that to someone who writes it back to the database and commits the transaction Outputs in our case are messages that get stored in the database, too (in order to allow recovering after transmission issues), so "output" in effect also just means "state". You don't always have to read "FP" in the strictest sense -- there's a spectrum to this. Now, if that code was written in such a way it would be easily testable and thus refactorable. In fact, most ideas in the clean/hexagonal architectures or "functional core, imperative shell" are to achieve exactly this. But since the author of said code never had any pushback, they just kept making an already grim situation worse with every change. For years. I see the same issue with the "ice nine" argument for async. If async infects all your business logic, chances are your abstractions suck. Edit: Also note that goroutines do effectively the same thing as synchronous code in a larger asynchronous function call: You group the code you can sensibly do in one go into a single goroutine. Then you pass the result to someone else to perform the next step. So, it's very often just another way to express the same process. CSP will invariably be a better abstraction for some problems, and async/await for others.
- meowaway 4y agoIt may be correct for some abstract mathematical concept of correct. But suppose your lang care about side effects and you want to track coloring for side effects. And then, it turns out there is a sporadic case where there is a performance regression and you want to do telemetry and produce spans to track the regression. Now you will want to blow your brains out because you will have to refactor all of your function calls down the chain. It could get even worse if at some point, you are passing a function to a library/framework and for whatever reason it refuses to tolerate a function of your color (assuming you can't lambda-ize the color). Now you have to rewrite the library. Or use a library that does tolerate it. Which might lose other features or ergonomics.