Hacker News new | ask | show | jobs
by bamfly 1104 days ago
Async in interface by default was a mistake and led to a ton of pain. Actually-async-under-the-hood is fine.

See: how much JS is rightly and justifiably littered with "await" on seemingly almost every line, now that that's an option. It's downright comical to look at, and as clear a sign of mis-design in a language/runtime as you can get. Nine times out of ten (maybe more...) you just need to treat all that async stuff as synchronous, from the perspective of the current block of code. "Await" or something like it should have been the default behavior of async calls. A great deal of the mess in Javascript over the last couple decades has been due to going the other direction with that default.

3 comments

> It's downright comical to look at, and as clear a sign of mis-design in a language/runtime as you can get.

That's your opinion. Some of us prefer to know when a call is I/O-constrained and when the execution queue is being interrupted. JS had fearless concurrency before it was cool.

When was the last time you heard of a JS program in a thread deadlock under load (other than a VM bug)? Never. It can get caught up in an infinite loop like any language, but that's not deadlocking. Because the language doesn't allow it. Not "makes it easier to avoid". Straight up doesn't allow it. That's no small thing, and it's not something Go can claim.

> Straight up doesn't allow it.

Right—so making the most-commonly-desired behavior (await-like behavior) default would have been a pretty big win, then, and not harmed that quality at all. Meanwhile it's only with the addition (and liberal sprinkling across most active JS codebases) of async/await that the default behavior doesn't result in ugly, awful code—wrestling with that defect is basically the story of the evolution of JS during and since the '00s. The number of person-hours lost to unwanted async-by-default semantics, writing competing libraries to work around it and make it less painful, learning those libraries, contorting code to use them just so you can (more often than not) cancel out the (perceived) effects of async behavior, learning the next set of libraries after that set's defunct, et c., must have been enormous—so incredibly large that I don't think there's any saving that decision from the "mistake" pile.

Now, it's merely funny and a little unsightly, seeing "await" rivaling, on a usage-count basis, keywords like "const" in so many JS codebases.

Straight up doesn't allow deadlocks.

> Right—so making the most-commonly-desired behavior (await-like behavior) default would have been a pretty big win, then, and not harmed that quality at all.

And you'd eliminate easy access to things like Promise.all, Promise.allSettled, and Promise.race. You'd also make it harder to see when the execution queue has a break.

If you want implicit awaits, Lua will welcome you with open arms. It is not to my liking.

localStorage is not async and it often causes problems because of that It seems to me what you are suggesting is implicit async (or rather automatic await insertion) which I guess could work. However I fail to see how it would make code easier to write or understand while actively increasing problems due to unclear async vs sync calls. Especially now that typecheckers can detect non-awaited calls.

Explicit await in a sense is documentation, sure 90% of async functions just do things sequentially, but the awaits in there are clear signs that "hey things won't happen instantaneously here"

also don't forget pretty much all similar event-loop systems in other languages also have explicit await calls