Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by
edited by

Think I’ve found a bug in core.async tests, the following test for mult working seems purely coincidental:

;; ASYNC-127 
(let [ch (to-chan! [1 2 3])
      m (mult ch)
      t-1 (chan)
      t-2 (chan)
      t-3 (chan)]
  (tap m t-1)
  (tap m t-2)
  (tap m t-3)
  (close! t-3)
  (is (= 1 (<!! t-1)))
  (is (= nil (a/poll! t-1))) ;; t-2 hasn't taken yet
  (is (= 1 (<!! t-2)))
  (is (= 2 (<!! t-1))) ;; now available
  (is (= nil (a/poll! t-1)))))

The docstring of core.async/mult states that: Items received when there are no taps get dropped. Following this statement, the 3 items put by to-chan! should be dropped, as when the mult is created, it would start consuming them without taps yet on the mult.My suspicion is that it passes because the go’s created inside mult and to-chan! might be slow enough to create so that the taps get executed before the mult starts consuming.

Does this make sense? Am I missing something?

EDIT: Found this issue https://clojure.atlassian.net/browse/ASYNC-246 which seems to be related, in that case probably hangs because the items might be properly dropped and then (<!! t-1) hangs

1 Answer

0 votes
selected by
Best answer

mult launches a go block internally. There is no happens-before relationship between that launched go block and the taps happening in the let binding. It is a perfectly normal ordering for the taps to happen before the mult starts distributing vals.

The test relies on an ordering that may accidentally happen.

You're right, the way I phrased it is not correct: `... items ... should be dropped` a more correct way would be `might get dropped` as being asynchronous either being dropped or accepted by taps are correct behaviours. The test seems unreliable either way, as it could fail whenever the ordering happens differently, maybe in a different setup (Likely what happens on https://clojure.atlassian.net/browse/ASYNC-246).