5/17/2025 at 5:47:09 PM
This proposal reeks of "What color is your function?" https://journal.stuffwithstuff.com/2015/02/01/what-color-is-... . The distinction between sync functions and async functions keeps intruding into every feature. As we can see here, there are Symbol.dispose and Symbol.asyncDispose, and DisposableStack and AsyncDisposableStack.I am so glad that Java decided to go down the path of virtual threads (JEP 444, JDK 21, Sep 2023). They decided to put some complexity into the JVM in order to spare application developers, library writers, and human debuggers from even more complexity.
by nayuki
5/17/2025 at 6:05:36 PM
I disagree. Hiding async makes reasoning about code harder and not easier. I want to know whether disposal is async and potentially affected by network outages, etc.by jupp0r
5/18/2025 at 2:45:40 AM
look into how React Suspense hides asynchrony (by using fibers). its very commingled with nextjs but the original ideas of why react suspense doesnt use promises (sebmarkbage had a github issue about it) is very compellingby swyx
5/18/2025 at 4:08:33 AM
Compelling? It's freaking terrible, instead of pausing execution to be resumed when a promise is resolved they throw execution and when the promise is resolved the whole execution runs again, and potential throws again if it hits another promise, and so on. It's a hacked solution due to the use of a global to keep track of the rendering context to associate with hook calls, so it all needs to happen synchronously. If they had passed a context value along with props to the function components then they could have had async/await and generator components.by notnullorvoid
5/20/2025 at 10:21:03 AM
This is fallacious. You could use the same logic to argue that we should encode the type of every argument and return value of a function into the function signature, and have to explicitly write it out by hand at every call site, for the same reason:x = number:foo(number:x, string:y)
It's absurd. The type system should responsible for keeping track of the async status of the function, and you should get that when hovering over the function in your IDE. It does not belong in the syntax any more than the above does and it's an absolutely terrible reason to duplicate all of your functions and introduce these huge headaches.
by throw10920
5/18/2025 at 4:58:09 AM
To be clear......This does not introduce function coloring.
You are mearly pointing out the effects of pre-existing function coloring, in that there are two related symbols Symbol.dispose and Symobl.asyncDispose.
Just like there is Symbol.iterator and Symbol.asyncIterator.
by paulddraper
5/18/2025 at 2:21:45 AM
That's a critique of `async`, not of `using` though, right? This doesn't seem to make functions more colored than they already are as far as I understand.by bla3
5/17/2025 at 7:34:48 PM
This is because normal execution and async functions form distinct closed Cartesian categories in which the normal execution category is directly embeddable in the async one.All functions have color (i.e. particular categories in which they can be expressed) but only some languages make it explicit. It's a language design choice, but categories are extremely powerful and applicable beyond just threading. Plus, Java and thread based approaches have to deal with synchronization which is ... Difficult.
(JavaScript restricts itself to monadic categories and more specifically to those expressible via call with continuation essentially)
by anon291
5/17/2025 at 9:01:14 PM
It’s so annoying that right now the state of the art is essentially “just write all of your code as async because even sync callers could just spin up a one-off event loop in the worst case” in most languages.The only language I know that navigates this issue well is Purescript, because you can write code that targets Eff (sync effects) or Aff (async effects) and at call time decide.
Structured concurrency is wonderful, but my impression is we’re doing all this syntactic work not to get structured concurrency, but mostly to have, like, multiple top-level request handlers in our server. Embarassingly parallel work!
by rtpg
5/18/2025 at 3:16:45 AM
Indeed. Virtual threads, structured concurrency and scoped values are great features.by dingi
5/17/2025 at 6:21:30 PM
In plain javascript it's not a problem. Types are ducked so if you receive a result or a promise it doesn't matter. You can functionally work around the "color problem" using this dynamism.It's only when you do something wacky like try to add a whole type system to a fully duck typed language that you run into problems with this. Or if you make the mistake of copying this async/await mechanism and then hamfistedly shove it into a compiled language.
by timewizard
5/17/2025 at 8:54:44 PM
Typescript has no problem with typing your scenario (or at least nothing that isn’t present in “plain” JavaScript… what if your value is a promise?)And compiled languages don’t have more trouble with this than JavaScript. Or rather, Javascript doesn’t have less issues on this front. The color issue is an issue at the syntactic level!
by rtpg
5/17/2025 at 11:54:49 PM
Except you can await on non-Promise objects which just returns the original object. Most other typed languages do not appear have this convenience. C# (the apparent source of the color rant) does not. It sets JavaScript apart.Likewise Promise.resolve() on a promise object just returns the original promise. You can color and uncolor things with far less effort or knowledge of the actual type.
by timewizard
5/18/2025 at 6:59:55 AM
Awaiting a non-promise doesn’t make it synchronous, though — it still executes any subsequent lines in a microtask.Try running this code. It’ll print “bar” first and then “foo”, even though the function only awaits a string literal and the caller doesn’t await anything at all.
const foo = async () => console.log(await "foo");
foo();
console.log("bar");
by jakelazaroff
5/18/2025 at 7:13:16 AM
In C# nothing stops you from doing `var t = Task.Run(() => ExpensiveButSynchronous());` and then `await`ing it later. Not that uncommon for firing off known long operations to have some other threadpool thread deal with it.Unless you literally mean awaiting non-awaitable type which...just doesn't make sense in any statically typed language?
by neonsunset
5/19/2025 at 5:09:01 AM
Please see https://news.ycombinator.com/item?id=44026655.by dang
5/17/2025 at 7:23:41 PM
Beyond happy Java made that decision as well.by vips7L
5/17/2025 at 9:01:44 PM
I'm not sure how it's implemented in the JVM, but in general, multithreading is notoriously difficult to reason about. Entire books are devoted to the pitfalls (race conditions, deadlocks, livelocks, starvation, memory visibility issues, and more). Compared to that, single threaded async programming is a walk in the park. I’d rather deal with "function color" than try to debug a heisenbug in a multithreaded app.by olalonde
5/17/2025 at 10:12:51 PM
Share-nothing via message passing ala Erlang makes multithreading much more tractable. I daresay it's enjoyable.Async is a decent syntax for simple tasks but that simplicity falls apart when composing larger structures and dealing with error handling and whatnot. I find it more difficult to understand what's going on compared to explicit threading.
by pton_xd
5/17/2025 at 10:26:30 PM
> Async is a decent syntax for simple tasks but that simplicity falls apart when composing larger structures and dealing with error handling and whatnot.Do you have a concrete example? It has just never really been an issue for me since async/await (callback hell was a thing though).
by olalonde
5/18/2025 at 4:31:54 PM
You don’t know how it works and are commenting on it?? Peak HN.by vips7L
5/18/2025 at 6:50:39 PM
Multithreading works similarly across most programming languages, and that was my assumption here as well. Your comment made me second-guess myself a bit, so I went back and checked the spec. Turns out it is indeed just standard multithreading, as I originally thought.by olalonde
5/19/2025 at 8:09:07 AM
The implementation and the observable behaviour are two different thingsby afiori