core-async

Gabriel 2025-10-02T13:51:54.101559Z

👋 I wonder why vthreads didn't remove the limitation around not doing blocking operations in go blocks.

2025-10-02T14:27:58.454239Z

IMO that would be a mess because of backward compatibility, different runtimes support, and straight confusing

Alex Miller (Clojure team) 2025-10-02T14:47:09.664939Z

you can use io-thread to gain these new capabilities

2025-10-02T20:52:51.661869Z

@jpmonettas it would still be backwards compatible no? Just not forward compatible

2025-10-02T22:51:58.995789Z

yeah, backwards compatible isn't the correct term there, but the thing is making the semantics of blocking operations depend on the runtime, runtime versions, and core.async version which I think is super confusing

2025-10-02T23:46:26.505819Z

Ya, I don't know. It just means you have to use a minimum JDK version and core async version. It's not much different than any other libs that use new features of the JDK.

2025-10-02T23:48:08.330509Z

But I respect just introducing a new macro. I just dislike that it's called io-thread but it's meant to replace both go and thread. If you're on JDK 21 and using the new core async, there's no reason to use go or thread unless you want to be forward compatible.

2025-10-02T23:49:21.612829Z

And I guess ClojureScript compatibility as well.

Alex Miller (Clojure team) 2025-10-03T00:37:52.687589Z

It is not meant to replace thread, which still is a platform thread, which sometimes is what you want

2025-10-03T00:47:44.162659Z

In exceptional cases, but current use of thread is for blocking IO, and io-thread would replace that use no?

Alex Miller (Clojure team) 2025-10-03T01:11:11.097009Z

You might still want a dedicated thread

2025-10-03T01:14:05.889779Z

Right, I like the option and I understand that thread will always use a platform thread no matter what settings and configuration. But it seems in the 99% case, you can just use io-thread exclusively for everything, channel ops, compute, async io, and blocking io

2025-10-02T16:08:42.619259Z

I'm working on (read: yak shaving) an http client library that I want to use to wrap a few http APIs. I want first class support for long running streaming responses (such as SSE, though implementing SSE would still be on the user/a higher layer, I want that to be natural with my library). I'm wondering what would a good "core.async native" approach would be here. I'm considering having a function like this:

(request http-client request-data channel close?)
;=> 
And on the channel, first a response map would be put (with e.g. :status/:headers, but NOT :body), and then subsequently some number of ByteBuffers, chunks of the body data, get put on the same channel (and then it gets closed if close? is true). How bad of an idea is this? Is it generally bad to have wildly different things put on the same chan like this (a map then bytebuffers)? Is it better to wrap the ByteBuffers in a map? Is it better to have request return a single response map containing :body, another channel (and I guess add body-chan optional args to request) Something else?

2025-10-02T16:37:20.267399Z

it is very similar to how netty's pipelines work

👀 1
2025-10-02T16:39:53.462399Z

I generally tend to towards wanting all messages to have some kind of common "framing", which might just be they are all maps with a :type key, but I can definitely see want to avoid add extra wrappers

2025-10-02T16:43:09.044179Z

the way say http works with netty is you have a pipeline and when there is a connection netty starts sending the netty equivalent of bytebuffers into the pipeline, and some stage in the pipeline consumes the bytes and turns them into various kinds of http messages (a message might contain the entire request, or just headers, or be part of a streaming body) and those http messages then continue on to the next stage of the pipeline

2025-10-02T17:01:49.386929Z

Thanks, hadn't considered netty much before but that does seem like what I'm going for. Now I wonder if I should just try to wrap that, if only to figure out how it works

2025-10-02T17:07:27.948769Z

a lot of my experience with netty is reaching into the guts of an existing netty server using reflection to grab the pipeline it defined and modify it. so it can be a nice flexible approach to defining sort of codecs, but you also get all of netty which dependency wise can be similar to depending on jackson. And I still have to stop and think really hard every time I need to figure out which way data flows "up" and "down" in a pipeline

👍 1
2025-10-02T17:09:05.815659Z

netty pipelines overlap a lot with "interceptors" as a concept