promise-chan
Description
Environment
Attachments
Activity
Stuart Sierra August 28, 2015 at 10:02 PM
Screened. Clojure version good, assuming ASYNC-124 is applied first. ClojureScript version may or may not need additional work.
I agree that the addition of close-buf!
and the no-op implementations feel like working around some missing abstraction. (What does it even mean to "close" a buffer?) But the Buffer
protocol is not part of the public API, it's buried down in clojure.core.async.impl.protocols
. The Channel and Buffer implementations are already tightly coupled, so adding another point of collaboration does not seem likely to cause problems. Adding close-buf!
is certainly preferable to duplicating the implementation of ManyToManyChannel
.
Alex Miller August 24, 2015 at 7:03 PM
I just confirmed with Rich that once delivered, a promise-chan should always deliver that value to takers, regardless of whether it is subsequently closed.
Alex Miller August 24, 2015 at 6:56 PM
Taking after delivery is intended. It is hard sometimes to know whether a take will happen before or after delivery in asynchronous systems so both must work. close! will deliver nil to all pending or future takers - in this case (as with all channels) nil indicates a drained channel, meaning that no delivery will ever happen.
However, one good question here is - what happens when you close a promise-chan that has already been delivered?
Currently:
(def pc (promise-chan))
take from promise-chan (blocks)
(>!! pc 5) - delivers 5 to blocked taker(s)
take from promise-chan (immediately returns 5) ;; for any number of takes
(close! pc 5)
take from promise-chan (immediately returns nil) ;; ???
I could easily be persuaded that the last answer is wrong and that it should always deliver 5 regardless of whether the pc gets closed (that is closing has no effect on delivered promise-chans).
Leon Grapenthin August 23, 2015 at 12:46 PM
It seems that there are two different approaches to how a promise-chan is supposed to or can be used.
1. All consumers are supposed to be takers before the promise is delivered. Taking after delivery is not intended, hence producers should close the channel after delivery.
2. " can take at any time and either have to wait for the promise (take blocks) or they get its value right away.
(2) models the behavior of real promises. (1) rather models that of a mutable reference.
It seems that the current patch explicitly makes room for (1) by giving producers the possibility to close.
Now if you want to use a promise-chan like (1) as a producer you can't create and return a promise-chan. Instead you need to be passed a promise-chan which has (a) taker(s) already. On the consumer side, it seems like an annoying quirk to enqueue takes before being able to pass the promise-chan to the producer (since he could close the promise immediately). I can't think of a scenario where one would want to do such thing. So my new question is:
Given the lengths taken here to enable (1), are there practical usecases for that? Why is closing a promise-chan not just going to be a no op?
Alex Miller August 12, 2015 at 9:00 PM
I believe that this patch can be re-evaluated after ASYNC-124 is applied as that patch addresses the reason this was retracted.
Details
Details
Assignee
Reporter
Approval
Patch
Priority

A
promise-chan
is a new kind of core.async channel that gives promise semantics to a channel.Takes block prior to put or close!
After a put, all pending takes are notified, and any subsequent takes return the put value immediately
After a close (and no put), all pending takes are notified with nil, and any subsequent takes return nil immediately
In practice, a
promise-chan
is a normal channel that uses apromise-buf
:buf can only take on one value (or nil if closed) ever
buf is never emptied: N consumers can all get the same, one and only value by reading from the channel
In order to make
close!
sensible with this new kind of bufall buffers need to be closeable
closing a channel closes its buffer
all basic buffer types do nothing when closed
a
promise-buf
make a one-time transition to having no value when closed (if not previously delivered)closing a buffer is implementation detail not exposed to end users
Approach:
Buffer protocol now has a close-buf! function (close! would have overlapped the Channel function close!). close-buf! is invoked on a buffer when the channel is closed, allowing it to update itself if necessary.
Existing buffers implement close-buf! and do nothing (buffer still available for taking)
New promise-buffer implementation. Makes a one-time transition when value is supplied or buffer is closed. value is held in an unsynchronized-mutable deftype field - updates via add!* or close-buf! always happen under the containing channel mutex.
New api functions:
promise-chan
creates a channel with a promise-buffer andpromise-buffer
.Patch: async-103-6.patch, async-103-cljs.patch (catches up cljs to diffs in async-103-6)