How about core.async is considered as harmful? What did you think?
I think core.async avoids that problem, since every go-block returns something you can wait and synchronize on. Since Clojure is expression based, everything is evaluated to a value in the end, so even a loop in a go block will eventually return a value which you can wait on.
core.async doesn’t solve the problem of your functions picking up a “color” but it does solve the problem described in the post.
The error propogation and resource cleanup issue still exists?
I think core.async can be considered a low-level building block. The error propagation can be fixed by a library on top of core.async (at least it seems like https://github.com/replikativ/superv.async do that). Regarding resource cleanup, I think there are two parts to this: If you keep a reference to the returned channel, as @bsless mentions, you can cleanup; the other part is that core.async runs on a fixed size thread-pool, which limits the amount of “dangling” IO (which is also discouraged in core.async as far as I remember).
I think error handling is left mostly up to the user, but you can use something like https://github.com/replikativ/superv.async if you want something richer.
Where would you say resource cleanup is lacking in core.async? If you open a file and pass the handler to a go-block, close and return, it’s the same problem as passing it to a thread, so I don’t think it’s unique to this context.
Edit: ninja’ed regarding superv by @mdiin
FWIW I think
core.async is much much more about channels than it is about
go is annoying to work with, there is absolutely no doubt about that.
In Clojure I barely use
go since I have the option to use the blocking operations instead. This works perfectly fine as long as you don’t create too many threads.
go is exactly about solving that problem though. What happens if you have to create thousands/millions of “threads”? The JVM can’t do that (yet) and in JS you can’t even spawn new ones at all. Technically Workers exist but they can’t share memory so they are in a totally different camp.
The “nursery” abstraction from the description also implies that you can block the calling thread. Otherwise you are just replacing once async thing with another but don’t solve the actual “blocking” problem. So since JS can’t block you are back to square one.
For the JVM the future is looking good with loom.
core.async will be just as useful then as it is now. Just probably won’t use
go at all anymore.
For JS we’ll be stuck with
Promise or callbacks … async code sucks to write but its what we are stuck with for the forseeable future.
Just a reminder, if you want to challenge your favorite framework against the concerns discussed in this post, you can write an implementation of the happy eyeballs protocol and share it here. That’s a very interesting and non-contrived problem and a good illustration of the benefits of supervision in the wild.
I see where he’s going with the idea, but I’m not 100% sold on it. The nursery idea is a beefed up version of Promise.all() or asyncio.gather(). I’d have to try some more real world things with it to see if it’s really that much better.
Java doesn’t have continuations, so it’s not an apples to apples comparison with Python or JS. Clojure’s async seems to be a wrapper around an underlying thread pool. That’s not the same as what async/await normally does.