core-async

weavejester 2026-03-26T13:45:32.899279Z

Is there a reason why pipe doesn't have an xform argument? I often find myself wanting to translate from one channel to another, but pipeline feels a little too heavy - I don't need to perform my computation on a separate (or multiple) threads.

Alex Miller (Clojure team) 2026-03-26T14:01:02.664179Z

I've had this conversation before (can't remember the context exactly) and I think there may be a gap here, but it needs some careful unpacking.

Alex Miller (Clojure team) 2026-03-26T14:01:25.765299Z

you can put the xform directly on a channel of course, and then combine with pipe - why does that not suffice?

Alex Miller (Clojure team) 2026-03-26T14:01:54.839189Z

(I'm asking this socratically, not trying to challenge you)

weavejester 2026-03-26T14:01:57.776119Z

Embarrassingly I had actually forgotten I could do that.

Alex Miller (Clojure team) 2026-03-26T14:02:34.208489Z

I think one answer would be that you already have the channels in hand (so too late to do that)

Alex Miller (Clojure team) 2026-03-26T14:04:54.094629Z

another problem that I know I've seen is that it can be important to AVOID ever having the producer run the xform, because the producer is a hot path and your intent is to decouple the "work" from the "putter". because xforms on a channel may run in either the producer thread or some other thread, you don't (usually) have this guarantee

Alex Miller (Clojure team) 2026-03-26T14:05:44.016379Z

so something of the shape of "pipe with xform" that has the property would perhaps be useful

weavejester 2026-03-26T14:11:44.960419Z

In my case I don't think there's much "work" - hence my reluctance to use pipeline. I tend to be reticent about parallelism if the workload is small, as past benchmarks tend to show functions like pmap are slower for small workloads. However, I think in my case I can use the channel xforms. I essentially have two channel pairs - a-in/a-out and b-in/b-out. I'm connecting a-in to b-out and b-in to a-out, with a translation between the two ends. I'm creating the B channels but not the A channels. However, if I put the translations on the B channels it should work, unless I have my logic all twisted.

weavejester 2026-03-26T14:13:08.071219Z

If I'm putting data into b-in, then the xform will transform it before sending it to a-out. Likewise if a-in receives data and places it into b-out, then the xform on b-out should transform it.

weavejester 2026-03-26T14:13:22.355219Z

Thanks for reminding me about channel xforms!

weavejester 2026-03-26T16:05:28.402709Z

Is there a way to wait on a channel to close without consuming from it? I'm asking because if I set up a pipe between two channels, and then want to do something after the pipe is closed, I'm unsure how to do that without writing my own custom pipe function (which may be the solution!)

Alex Miller (Clojure team) 2026-03-26T16:18:33.437709Z

this is consuming (so definitely violates your ask), but take will deliver nil when closed

Alex Miller (Clojure team) 2026-03-26T16:18:55.896229Z

(nil is not allowed as a channel value, so it always represents close)

weavejester 2026-03-26T16:19:04.672679Z

I guess a side-effectful reducer on the channel could do it... though that seems like bad practice?

weavejester 2026-03-26T16:20:59.984509Z

(defn side-effect-on-reduced [side-effect]
  (fn [rf]
    (fn ([] (rf))
     ([result] (side-effect) (rf result))
     ([result x] (rf result x)))))

Alex Miller (Clojure team) 2026-03-26T16:25:09.173349Z

I'm not sure the completing arity ever get called in channel transducers

weavejester 2026-03-26T16:25:49.252339Z

I just tested it and it actually does, though whether that's a guarantee in future I don't know.

weavejester 2026-03-26T16:36:21.546479Z

Would it be useful to have a function in core.async that waits for a channel to be closed? It could operate the same was as timeout, in that it returns a channel that closes when its argument channel is closed.

(<! (a/wait-until-closed ch))
This seems analogous to the Thread.join method.