Hacker News new | ask | show | jobs
by preommr 16 days ago
> You still can’t call a function that returns a future from synchronous code. (Well, you can, but if you do, the person who later maintains your code will invent a time machine, travel back in time to the moment that you did this and stab you in the face with a #2 pencil.)

Author makes up a lie.

Then lampshades it away with a colorful non sequitur.

---

The alternatives that people praise like golang, have other tradeoffs that are much worse because the async logic is now implicit. Your entire codebase is now a surface area that is at risk of being blocked by waiting on a channel; the the mitigation of this is through responsible use of coroutines, but then you're right back around to extra information about your code that is analogous to colring, except not as explicit as async/await.

3 comments

I don't see how that's a lie; calling an async function from synchronous code is generally a mistake. There are cases where it's appropriate but it's rare
Your entire codebase is already at risk of being blocked by a spinlock or CPU-intensive operation, so what's the difference?
If you haven’t taken a lock, any other code can start executing at any time, so any invariant you might have established on one line may no longer be true on the next line.

If you don’t depend on anything mutable that anyone else can modify then this is mitigated, but that’s a very specific discipline you have to abide by.

> Your entire codebase is now a surface area that is at risk of being blocked

The point of goroutines is that they can freely block when needed. It's not like async where you have to be paranoid at every moment about writing blocking code

Why would there be paranoia when writing blocking code with async?

The downside of goroutines is that you have no control when the goroutine context switches, so naively accessing a global value can lead to race conditions (which the language has no warnings for despite being such a concurrent language), while the same code works fine in JavaScript because context switches don't happen in synchronous code.

> Why would there be paranoia when writing blocking code with async?

In languages like JavaScript, you have to be careful to avoid blocking the event loop, and use something like worker threads for CPU-intensive tasks. Otherwise you will end up with long tail latencies. In Go, the runtime automatically manages this and can suspend and resume long-running goroutines.

> naively accessing a global value can lead to race conditions

Fair point that the language doesn't automatically catch this, but that's what a mutex is for. In return you get actual parallelism that can use all your CPU cores

Amusingly, Go, a language designed for concurrent programming, also had problems with blocking code for years. They had two releases that fixed it with proper preemption (1.2 added preemption, and 1.14 fixed other issues with preemption).
You can only freely block the goroutines that you designed that way, there's plenty of ways of shooting yourself in the foot with goroutines without even touching “blocking” code (because everything is blocking).