transducer not applied with unbuffered channels

Description

Found this while testing some stuff on ASYNC-124.

Cause: For an unbuffered channel, a take will try to pair up with a put, in which case the two are satisfied directly without ever involving the buffer (since there isn't one). Because of this, add! is never called and the xf will not be applied. The example above uses an expanding transducer, but problem exists for any transducer and could perhaps happen even on buffered channels?

Approach: one approach would be to not satisfy the put unless there were enough pending takes to satisfy all the transduced values, which seems consistent with an unbuffered channel.

Environment

None

Activity

Show:

Alex MillerNovember 5, 2015 at 3:17 AM

After talking to Rich, it is considered an error to created a fixed buffer of size 0 and that should throw. The ticket ASYNC-143 covers that check.

On the last question, a transducer needs to be (potentially) be able to produce multiple values with something like a mapcat transducer. Without a buffer, there is no place for those buffers to go, so an unbuffered channel is insufficient.

importNovember 4, 2015 at 11:10 PM

Comment made by: alex.nixon

I vote to reopen this.

As a user this feels like a very subtle bug - the docstring says "if a transducer is supplied, a buffer must be specified". In your example you have specified a buffer – one of size zero – and so it's very surprising when you find out (at some later stage in your program) that your transducer was silently ignored. If a fixed buffer of size zero is not a valid thing to construct then I would expect (buffer 0) to throw an IllegalArgumentException or similar.

And philosophically I don't understand why the combination of an unbuffered channel and a transducer should be forbidden. What's the argument here?

Alex MillerAugust 18, 2015 at 2:17 PM

I'm a dope and unbuffered channels (or 0-sized fixed buffer) channels do not support transducers per the chan docstring.

Alex MillerAugust 17, 2015 at 11:13 PM

I suspect the problem is here:
https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async/impl/channels.clj#L115-L133

where a take can't get a value from the buffer (there is none) and instead satisfies itself by matching up directly with a put. In this case, add! is never called so the transducer is not applied.

In the case of an expanding transducer, a buffer is needed at this point where none exists.

Declined

Details

Assignee

Reporter

Approval

Triaged

Priority

Created August 17, 2015 at 9:29 PM
Updated November 19, 2018 at 9:25 PM
Resolved November 19, 2018 at 9:25 PM