<< Back to previous view

[ASYNC-124] put! into channel that has mapcat transducer fails to dispatch more than one waiting takes Created: 30/May/15  Updated: 28/Oct/15  Resolved: 28/Oct/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: Jozef Wagner Assignee: Alex Miller
Resolution: Completed Votes: 1
Labels: None
Environment:

Clojure 1.7.0-RC1, latest core.async head (May 2015)


Attachments: Text File async-124-2.patch     Text File async-124-3.patch     Text File async-124-4.patch     Text File async-124-5.patch     Text File async-124-6.patch     Text File async-124-7.patch     Text File async-124-8.patch     Text File async-124.patch    
Patch: Code and Test
Approval: Ok

 Description   

This issue is similar to one that has caused the revert of ASYNC-103. When channel has multiple pending takes, one put will dispatch only one take, even if transducer attached to the channel produces multiple values.

(require '[clojure.core.async :refer (chan put! take!)])
(let [xf (mapcat #(range % (+ % 5)))
        c (chan 10 xf)]
    (dotimes [x 5]
      (take! c #(println (str x %))))
    (put! c 10)
    (put! c 15))

The output of the above code is

0 10
1 11

but it should be

0 10
1 11
2 12
3 13
4 14

Note that if we change the order and execute puts before takes, the result will be as expected.

Cause: When executing a write on a channel, no more than one pending take will be satisfied. Other pending takes will wait until the next put. When a put could release at most one take, this was sufficient but with expanding transducers, a put can potentially satisfy many pending takers.

Approach: Once a put succeeds into the buffer (through the transducer), instead of finding a single taker, do the prior work in a loop, pairing up callbacks with values removed from the buffer. Once the loop is complete, release the mutex and dispatch all paired takes.

Patch: async-124-8.patch

Screened by:



 Comments   
Comment by Jozef Wagner [ 30/May/15 10:30 AM ]

patch with test

Comment by Jozef Wagner [ 30/May/15 10:32 AM ]

Note that with attached patch the actual dispatch/run on takes happens before (.unlock mutex) and before (when done? (abort this)) are called.

Also note that added test only works with 1.7.0 version of clojure

Comment by Jozef Wagner [ 30/May/15 12:46 PM ]

Added new patch async-124-2.patch that dispatches after unlocking and aborting. Test was also changed as it had race condition.

Comment by Alex Miller [ 06/Jul/15 9:23 AM ]

We can't add a test that is 1.7-only. See https://github.com/clojure/core.async/blob/master/src/test/clojure/clojure/core/pipeline_test.clj#L7 for an example of how to patch in a transducer impl that will work in pre-1.7.

Comment by Jozef Wagner [ 06/Jul/15 10:41 AM ]

Added async-124-3.patch that works with Clojure <1.7

Comment by Alex Miller [ 10/Aug/15 3:53 PM ]

Jozef, I don't see any reason why the independent callbacks in your test will necessarily conj in order as they contend for the atom. When I run the test I usually get a failure. If you agree, could wrap expected and actual in a set. Or if that seems wrong, then let's decide why.

Comment by Jozef Wagner [ 11/Aug/15 10:49 AM ]

Attached async-124-4.patch that uses unordered comparison in test

Comment by Alex Miller [ 14/Aug/15 1:01 PM ]

Added async-124-5.patch which should be semantically identical as -4 but retains the structure of a single dispatch point.

Comment by Alex Miller [ 14/Aug/15 3:03 PM ]

New -6 patch tries to retain more of the original algorithm and leverages the original loop instead of adding a new one.

Comment by Alex Miller [ 18/Aug/15 8:25 AM ]

New -7 patch addresses some bugs in the prior version and cleans up the loop code, also adds better tests.

Comment by Alex Miller [ 28/Aug/15 11:53 AM ]

test tweaks added in -8, per Stuart Sierra

Comment by Stuart Sierra [ 28/Aug/15 12:01 PM ]

Screened. Clojure version good. Still needs corresponding fix to ClojureScript version.





[ASYNC-173] Infinite loop in go block when non-Exception thrown Created: 08/Aug/16  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: Matt Keller Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: try-catch
Environment:

core.async 0.2.385; clojure 1.9.0-alpha6



 Description   

A Throwable - other than Exception - thrown from a go block can cause an infinite loop.

(defn endless-fun [f]
  (let [in-ch (a/to-chan (range 1 10))]
    (->>
     (a/go
       (try
         (loop []
           (when-let [value (a/<! in-ch)]
             (f value)
             (recur)))
         (catch Exception e
           (.printStackTrace e)
           (throw e))))
     (a/<!!))))


(endless-fun (fn [i] (println i))) => 1, 2, ... 9

(endless-fun (fn [i] (println i) (throw (RuntimeException. (str i))))) => 1 

(endless-fun (fn [i] (println i) (throw (Throwable. (str i))))) => 1, 1, 1, ... infinite loop!

If the try/catch is absent, you don't get an infinite loop - it looks like the RuntimeException case above.

May also be related to http://dev.clojure.org/jira/browse/ASYNC-100 or http://dev.clojure.org/jira/browse/ASYNC-169.



 Comments   
Comment by Alex Miller [ 13/Feb/17 2:31 PM ]

Marking as a duplicate of ASYNC-169, which seems to fix this issue.





[ASYNC-169] Try/catch block loops eternally inside go block Created: 16/May/16  Updated: 22/Feb/17  Resolved: 22/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: Frank Burnham Assignee: Kevin Downey
Resolution: Completed Votes: 9
Labels: try-catch
Environment:

Clojure 1.7.0; core.async 0.2.374; java 1.8


Attachments: Text File 0001-overhaul-exceptions-in-clojure-go-macro-ASYNC-169.patch     Text File 0005-Turn-tag-class-in-to-symbol-ASYNC-169.patch     Text File 0006-Turn-tag-class-in-to-string-ASYNC-169.patch     Text File 0010-overhaul-exceptions-in-clojure-go-macro-ASYNC-169.patch     Text File ASYNC-169-4.patch    
Patch: Code and Test
Approval: Ok

 Description   
(a/<!!
    (a/go-loop []
      (try
        (a/<! (throw (Exception. "Ex")))
        (catch clojure.lang.ExceptionInfo ei
          :retry))))

The above example appears to loop forever when I expected it to return nil.

(a/<!!
    (a/go-loop []
      (try
        (throw (Exception. "Ex"))
        (catch clojure.lang.ExceptionInfo ei
          :retry))))

This example returns nil.

Related tickets:

Patch: 0010-overhaul-exceptions-in-clojure-go-macro-ASYNC-169.patch



 Comments   
Comment by Kevin Downey [ 16/May/16 3:50 PM ]

it looks like maybe "process-exception" in clojure.core.async.impl.ioc-macros is missing an :else (throw exception) clause at the end.

Comment by Frank Burnham [ 17/May/16 7:12 AM ]
user> (a/<!!
       (a/go-loop []
                  (try
                     (a/<! (throw (Exception. "Ex")))
                   (catch clojure.lang.ExceptionInfo ei
                          :retry) 
                   (catch Throwable t :drop))))
nil
user>

That example is also odd to me. I expected to see :drop returned.

Comment by Kevin Downey [ 17/May/16 12:07 PM ]

looking at the macro expansion for the two catches, the emitted code is only setting up an exception frame for the ExceptionInfo case, and not for the Throwable case.

I suspect the exception handling code is all sawdust and broken promises.

Comment by Kevin Downey [ 17/May/16 12:12 PM ]

this looks like it is ignoring everything except the first catch https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async/impl/ioc_macros.clj#L709

Comment by Kevin Downey [ 17/May/16 7:33 PM ]

this patch seems to make everything work, needs more tests of course

Comment by Kevin Downey [ 17/May/16 7:55 PM ]

looks like this might be the same issue as http://dev.clojure.org/jira/browse/ASYNC-100, which also has a patch attached

Comment by Alexey Aristov [ 10/Jul/16 11:36 AM ]

are there any plans/estimations regarding this bug? we were recently hit by it, and was a very special pleasure to analyze the issue.

Comment by Kevin Downey [ 20/Sep/16 11:38 AM ]

new patch, includes tests

Comment by Roman Pearah [ 09/Nov/16 9:33 PM ]

Wow, this is huge. My try block was just replaying over and over for no discernible reason, all without anything new coming off the channel (or anything prior to the try block executing). Stumped me for a while until I found this. Switching to catching Throwable instead of Exception worked as a quick fix.

Comment by Alex Miller [ 13/Feb/17 2:17 PM ]

Kevin Downey Hey, I've been looking at this, had a couple questions.

1) Does something similar need to be done for cljs?

2) There are a couple minor whitespace issues in the tests - you'll see the warning if you 'git apply' the patch - just need to remove trailing whitespace in a couple places.

3) I see these new reflection warnings from the new tests. Can these be avoided by typehinting to the type of the exception being caught inside the ?

Reflection warning, clojure/core/async/ioc_macros_test.clj:71:18 - reference to field getMessage can't be resolved.
Reflection warning, clojure/core/async/ioc_macros_test.clj:69:51 - reference to field getMessage can't be resolved.
Reflection warning, clojure/core/async/ioc_macros_test.clj:67:53 - reference to field getMessage can't be resolved.
Comment by Alex Miller [ 13/Feb/17 2:34 PM ]

The example in ASYNC-173 is another cases that causes a reflection warning on .printStackTrace.

Comment by Kevin Downey [ 13/Feb/17 3:54 PM ]

Latest patch fixes reflection on caught exceptions

Comment by Alex Miller [ 13/Feb/17 3:56 PM ]

thanks - for future reference, please add a -2 or something on the end so the patches aren't the same name (too easy to apply the wrong one). No need to do anything here though.

Comment by Kevin Downey [ 13/Feb/17 3:57 PM ]

Latest patch fixes trailing whitespace errors

Comment by Kevin Downey [ 13/Feb/17 4:00 PM ]

As for cljs, I am not sure, a quick glance has not filled me with confidence. I suppose it should be put through its paces with a similar set of tests. Off the bat it looks like the code only looks for one catch clause, which could be a problem, but maybe something up the line is turning multi-clause catches in to single clause catches for it.

Comment by Alex Miller [ 13/Feb/17 4:51 PM ]

For the examples up in the description:

  • the first example invokes <! with no channel, so seems broken to start (with patch applied, it throws)
  • the second example after patch is applied, throws as well.

I did not expect either example to throw.

Comment by Kevin Downey [ 13/Feb/17 5:26 PM ]

I don't follow

When I run the example I get a nil result (taking from a closed channel with nothing on it because the go-loop threw an exception). I get no new exception bound to *e, because the exception happened in the go loop thread, not the repl thread. And I get a print out of the exception thrown on the core.async thread because of core.async's default exception handling.

The exception bubbles out of the go block because the catch is for ExceptionInfo, but Exception is being thrown.

Is some part of that incorrect, or does it not match what you get when you run the example?

user=> (require '[clojure.core.async :as a])
nil
user=> (a/<!!
  #_=>     (a/go-loop []
  #_=>       (try
  #_=>         (a/<! (throw (Exception. "Ex")))
  #_=>         (catch clojure.lang.ExceptionInfo ei
  #_=>           :retry))))
Exception in thread "async-dispatch-1" java.lang.Error: java.lang.Exception: Ex
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1148)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.Exception: Ex
        at user$eval8675$fn__8693$state_machine__6725__auto____8694$fn__8697.invoke(form-init491495474467240539.clj:2)
        at user$eval8675$fn__8693$state_machine__6725__auto____8694.invoke(form-init491495474467240539.clj:2)
        at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:972)
        at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:976)
        at user$eval8675$fn__8693.invoke(form-init491495474467240539.clj:2)
        at clojure.lang.AFn.run(AFn.java:22)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        ... 2 more
nil
user=> *1
nil
user=> *e
nil
user=>
Comment by Alex Miller [ 14/Feb/17 10:01 AM ]

Got it. This example from ASYNC-180 doesn't seem to be doing the right thing now:

(def t3
  (go
    (try
      1
      (finally
        (<! (timeout 100))
        2))))

(println (<!! t3))
;; expect: 1
;; got: IllegalArgumentException No implementation of method: :take! of protocol: #'clojure.core.async.impl.protocols/ReadPort found for class: clojure.lang.Var$Unbound
Comment by Alex Miller [ 14/Feb/17 10:08 AM ]

Never mind, I must have had something weird referred in the midst of my example set.

Comment by Alex Miller [ 14/Feb/17 10:11 AM ]

Applied

Comment by Kevin Downey [ 14/Feb/17 1:41 PM ]

great news, thanks!

Comment by Kevin Downey [ 16/Feb/17 2:12 PM ]

I re-opened this issue due to a bug discussed on slack

(async/go
  (try
    (catch Exception e
      (async/<! 1)
      e)))

doesn't compile

Comment by Kevin Downey [ 16/Feb/17 2:14 PM ]

The latest patch (0003-Don-t-clobber-existing-metadata-ASYNC-169.patch) fixes the issue in my previous comment, and should apply cleanly to master.

Comment by Alex Miller [ 17/Feb/17 9:04 AM ]

When I apply the patch, tests don't run:

Exception in thread "main" clojure.lang.ExceptionInfo: Could not resolve var: ne {:var ne, :file "clojure/core/async/ioc_macros_test.clj", :column 9, :line 94}, compiling:(clojure/core/async/ioc_macros_test.clj:91:6)
Comment by Alex Miller [ 17/Feb/17 9:18 AM ]

Updated last patch to fix typo

Comment by Alex Miller [ 17/Feb/17 9:24 AM ]

I'm seeing a reflection warning here that does not seem expected (example from ASYNC-173):

(require '[clojure.core.async :as a :refer [chan go go-loop <! >! <!! >!! take! put! timeout]])
(defn endless-fun [f]
  (let [in-ch (a/to-chan (range 1 10))]
    (->>
     (a/go
       (try
         (loop []
           (when-let [value (a/<! in-ch)]
             (f value)
             (recur)))
         (catch Exception e
           (.printStackTrace e)
           (throw e))))
     (a/<!!))))

Reflection warning, /private/var/folders/7r/_1fj0f517rgcxwx79mn79mfc0000gn/T/form-init4526179122097363504.clj:11:12 - reference to field printStackTrace can't be resolved.
Comment by Kevin Downey [ 17/Feb/17 10:42 AM ]

0005-Turn-tag-class-in-to-symbol-ASYNC-169.patch applies cleanly to master(v0.2.395-19-g6e36258), and the tests pass so no typos. As I mentioned in slack, in the previous patch I changed how the tag metadata is attached, and ended up attaching a class instead of a symbol

Comment by Kevin Downey [ 17/Feb/17 11:29 AM ]

0006-Turn-tag-class-in-to-string-ASYNC-169.patch replaces the 0005 patch with improvements suggested by Bronsa in slack

Comment by Kevin Downey [ 17/Feb/17 12:39 PM ]

as discussed in slack, 0010-overhaul-exceptions-in-clojure-go-macro-ASYNC-169.patch combines all previous changes and applies cleanly against master (v0.2.395-22-g3e37e0b, all 169 changes reverted)





[ASYNC-138] Go blocks leak memory Created: 10/Aug/15  Updated: 22/Feb/17  Resolved: 22/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: Brian Lubeski Assignee: Unassigned
Resolution: Completed Votes: 14
Labels: go, memory
Environment:

clojure 1.7.0
core.async 0.1.346.0-17112a-alpha
Java HotSpot(TM) Client VM 1.8.0_31-b13


Attachments: Text File 0001-ASYNC-138-allow-for-clearing-of-closed-over-locals.patch     Text File 0001-ASYNC-138-allow-for-clearing-of-closed-over-locals-v2-nested.patch     Text File 0001-ASYNC-138-allow-for-clearing-of-closed-over-locals-v2.patch     Text File 0001-ASYNC-138-allow-for-clearing-of-closed-over-locals-v3.patch     Text File 0001-ASYNC-138-allow-for-clearing-of-closed-over-locals-v4.patch     Text File 0001-ASYNC-138-allow-for-clearing-of-closed-over-locals-v5.patch     Text File 0001-ASYNC-138-allow-for-clearing-of-closed-over-locals-v6.patch    
Patch: Code and Test
Approval: Vetted

 Description   

The following example, after running for a few minutes, generates an OutOfMemoryError.

(let [c (chan)]
  (go (while (<! c)))
  (let [vs (range)]
    (go
      (doseq [v vs]
        (>! c v)))))

By contrast, the following example will run indefinitely without causing an OutOfMemoryError.

(let [c (chan)]
  (go (while (<! c)))
  (go
    (let [vs (range)] 
      (doseq [v vs]
        (>! c v)))))

The only significant difference I see between the two examples is that the (range) is created outside the go block in the first example but is created inside the go block in the second example. It appears that the go block in the first example is referencing vs in such a way as to prevent if from being garbage-collected.

This behavior is also be the cause of ASYNC-32.

Approach:
The attached patch applies a transformation from

(let [a large-seq] (loop [..] .. a ..))
where the loop exemplifies the state machine loop created by `go`, into
(let [a large-seq a' (^:once fn* [] a)] (loop [..] .. (let [a (a')] ..) ..))

which allows the closed over locals to cross into the state machine loop without getting held. While this might look unsafe, because of how the `go` loop state machine works, we're guaranteed that `(a')` will only be invoked on the first iteration of the loop.
The patch looks way more complex than it actually is, because it needs to deal with: renaming locals so that shadowing of special symbols works properly, preserving locals type hints and handle nested go blocks, where the value of `&env` will be provided by tools.analyzer rather than from Compiler.java

There are two different type propagations that we need to do, one in case of non primitive objects and one in the case of primitive values:

  • if we're propagating type info for a non primitive object, the transformation is as follow:
    (let [a ^Klass my-obj] (loop [..] .. a ..))
    ->
    (let [a ^Klass my-obj a' (^:once fn* [] a)] (loop [..] .. (let [^Klass a (a')] ..) ..))
  • if we're propagating type info for a primitive local, a type hint won't do – we actually need to unbox the value out of the thunk, so the transformation will be:
(let [a (int x)] (loop [..] .. a ..))
->
(let [a (int x) a' (^:once fn* [] a)] (loop [..] .. (let [a (clojure.core/int (a'))] ..) ..))

Patch: 0001-ASYNC-138-allow-for-clearing-of-closed-over-locals-v6.patch



 Comments   
Comment by Nicola Mometto [ 15/Dec/15 9:34 AM ]

attached is a WIP patch to fix this issue, would appreciate some testing on this

Comment by Nicola Mometto [ 15/Dec/15 5:52 PM ]

CLJ-1744 contributes to this bug

Comment by Nicola Mometto [ 15/Dec/15 6:23 PM ]

Updated patch to preserve type info

Comment by Nicola Mometto [ 17/Dec/15 10:16 AM ]

Note that the current patch breaks nested `go` blocks at compile time since the nested `go` block will be macroexpanded by tools.analyzer.jvm rather than Compiler.java and this &env will be different.

Is this something we want to support? There seem to be a lot of other cases that break when nesting `go` blocks.

If this is something that we do want to support 0001-ASYNC-138-allow-for-clearing-of-closed-over-locals-v2-nested.patch fixes this

Comment by Jan Rychter [ 21/Dec/15 6:18 AM ]

This just bit me badly when doing data processing work — I never expected that (async/to-chan (line-seq rdr)) can be the culprit of my heap getting exhausted in 30 seconds. Took quite some time to narrow it down. Thanks to Nicola for letting me know about this bug on Slack.

Comment by Alex Miller [ 13/Feb/17 3:31 PM ]

Nicola, not sure how to read your comments above re the patches. Most of the other cases of nested go blocks failing that I see in the tracker are related to the exception handling bugs in ASYNC-169. Do you have any hesitancy over your patch for the nested stuff?

Comment by Nicola Mometto [ 13/Feb/17 3:40 PM ]

Alex, I think the only reason why I proposed the -nested patch as an alternative rather than as a main patch is that it adds complexity to the patch to handle an unlikely scenario. I think we should go with the -nested patch, but if understanding the patch for screeners is more important than handling weird edge cases, the other patch is easier

Comment by Alex Miller [ 13/Feb/17 3:55 PM ]

Tests don't pass with -nested patch.

Caused by: java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to java.util.Map$Entry
	at clojure.lang.APersistentMap$ValSeq.first(APersistentMap.java:232)
	at clojure.lang.RT.first(RT.java:653)
	at clojure.core$first__4110.invoke(core.clj:55)
	at clojure.core.async.impl.ioc_macros$state_machine.invoke(ioc_macros.clj:1107)
	at clojure.core.async.ioc_macros_test$runner.doInvoke(ioc_macros_test.clj:24)
Comment by Nicola Mometto [ 13/Feb/17 5:04 PM ]

updated patch making all the tests run

Comment by Nicola Mometto [ 14/Feb/17 4:49 AM ]

updated patch with an additional testcase making sure nested go blocks work properly after the transformation, also bumping tools.analyzer.jvm to the last version as that includes a fix for nested t.a calls

Comment by Alex Miller [ 14/Feb/17 10:40 AM ]

Applied.

Comment by Alex Miller [ 15/Feb/17 3:36 PM ]

I am reopening this and reverting the change for the moment. This example fails when using Clojure 1.9.0-alpha12+ (anything after the commit for CLJ-1224).

(require '[clojure.core.async :refer (go)])
(defprotocol P
  (x [p]))

(defrecord R [z]
  P
  (x [_]
    (go
      (loop []
        (recur)))))

CompilerException java.lang.UnsupportedOperationException: Can't type hint a primitive local

I believe this is due to the code in the patch related to applying meta to the local binding, specifically this comes into interaction with the code now generated in hasheq after CLJ-1224.

Comment by Nicola Mometto [ 15/Feb/17 4:58 PM ]

Updated the patch to handle with primitive type hints.
In case of primitive type hints, rather than emitting

(let [^String a (a')] ..)
we emit
(let [a (clojure.core/int (a'))] ..)
as hinting is not valid and proper unboxing is required

Comment by Alex Miller [ 15/Feb/17 8:12 PM ]

Did you mean to have ^String and clojure.core/int in that example?

Comment by Nicola Mometto [ 16/Feb/17 3:12 AM ]

yes, to showcase the two different transformations we do in case of primitive or non primitive type propagation. I'll expand on that in the ticket description so it's clearer what i meant

Comment by Alex Miller [ 17/Feb/17 9:10 AM ]

Applied v5 version.





[ASYNC-5] Go macro fails on quoted lists Created: 15/Jul/13  Updated: 16/Jul/13  Resolved: 16/Jul/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Brandon Bloom Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None


 Description   

Minimal reproduction:

(go '(1 2 3))

Error:

Exception in thread "async-dispatch-6" java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn



 Comments   
Comment by Timothy Baldridge [ 16/Jul/13 7:46 AM ]

Fixed in master: https://github.com/clojure/core.async/commit/403d2cf1812f51bacd42130d5509fc881d44e4bc





[ASYNC-1] String representation for channels Created: 11/Jul/13  Updated: 12/Jul/13  Resolved: 11/Jul/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Pepijn de Vos Assignee: Rich Hickey
Resolution: Declined Votes: 0
Labels: None

Attachments: Text File 0001-string-representation-for-channels.patch    
Patch: Code

 Description   

When working with channels, I frequently have no idea what's inside it and who's blocking on it.

This simple patch shows the number of items in the buffer, as well as the number of putters and takers.



 Comments   
Comment by Timothy Baldridge [ 11/Jul/13 9:13 AM ]

It should be noted that this patch simply adds .toString to the channel type. It does not provide extra members such as count-takers, or count-putters. I would have serious problems with the latter, but simply adding .toString seems very much in line with what we already have for atoms. The output of .toString can be out of date the moment the function is executed, but since it's only really useful for debugging anyways, I don't think we care.

Comment by Timothy Baldridge [ 11/Jul/13 9:23 AM ]

As the docs for LinkedList notes, these structures are not thread-safe (hence all the locking done in put/take).

http://docs.oracle.com/javase/6/docs/api/java/util/LinkedList.html

So this patch runs the danger of something going really wrong.

Comment by Pepijn de Vos [ 12/Jul/13 3:07 AM ]

What could go wrong? Count is not a structural modification, right? Or can you corrupt a list by merely taking its count while someone else is adding a thing?

If the general idea of a readable toString method sounds good, I'd be happy to add locking if necessary.





[ASYNC-7] Recur fails within case Created: 15/Jul/13  Updated: 16/Jul/13  Resolved: 16/Jul/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Brandon Bloom Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None


 Description   

Minimal reproduction:

(go (loop [] (case 1 1 (recur))))

Produces error:

IllegalArgumentException No implementation of method: :emit-instruction of protocol: #'clojure.core.async.impl.ioc-macros/IEmittableInstruction found for class: clojure.core.async.impl.ioc_macros.Jmp clojure.core/-cache-protocol-fn (core_deftype.clj:541)



 Comments   
Comment by Timothy Baldridge [ 16/Jul/13 7:37 AM ]

Fixed in master. https://github.com/clojure/core.async/commit/9ac00f931ba86fbfbcbec60e43e101796b8d5130





[ASYNC-9] nested 'go' blocks doesn't seems to work very well Created: 15/Jul/13  Updated: 19/Jul/13  Resolved: 19/Jul/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nahuel Greco Assignee: Rich Hickey
Resolution: Completed Votes: 0
Labels: None
Environment:

Clojure 1.5.1 / core.async 0.1.0-SNAPSHOT



 Description   

This raises an IllegalArgumentException:

(go
(go
(<! (timeout 2000))
true))

But this seems to work ok:

(go (go true))



 Comments   
Comment by Timothy Baldridge [ 15/Jul/13 11:28 PM ]

Works fine in master (latest from core.async github) please try a fresh checkout.

Comment by Nahuel Greco [ 16/Jul/13 12:14 AM ]

Thanks, Now it works ok.

Comment by Timothy Baldridge [ 19/Jul/13 8:50 AM ]

Closing as something in master has fixed the issue.





[ASYNC-16] Faulty rebinding of loop bindings in go macro Created: 01/Aug/13  Updated: 03/Aug/13  Resolved: 03/Aug/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Ghadi Shayban Assignee: Ghadi Shayban
Resolution: Completed Votes: 0
Labels: None

Patch: Code and Test

 Description   

Below from https://groups.google.com/d/msg/clojure/MJc-69TgjR0/9HZqE7-kM9UJ

There seems to be an issue with the rebinding of loop-bindings using loop/recur in go blocks,
specifically when you are just changing the order of the original bindings in a recur call.

Take this snippet for example:
(require '[clojure.core.async :refer [go timeout]])
(go (loop [a :black, b :white]
(println a b)
(<! (timeout 1000))
(recur b a)))

Instead of repeatedly printing

:black :white
:white :black
:black :white
:white :black
(...)

it actually prints

:black :white
:white :white
:white :white
:white :white
(...)

Note however, that

(require '[clojure.core.async :refer [go timeout]])
(go (loop [a :black, b :white]
(println a b)
(<! (timeout 1000))
(recur (identity b) (identity a))))

works correctly.



 Comments   
Comment by Ghadi Shayban [ 03/Aug/13 1:45 PM ]

Root cause:
Recurring with (recur b a) will emit semantically invalid code.
essentially
(let [b a
a b]

instead of something like:
(let [temp-b b
b a
a b]

Preliminary patch is on branch ASYNC-16.

TODO: add basic test and port the patch to cljs

Comment by Ghadi Shayban [ 03/Aug/13 2:06 PM ]

fixed with tests + cljs port.





[ASYNC-3] set! usage in ClojureScript go block results in set locals error Created: 11/Jul/13  Updated: 09/Aug/13  Resolved: 09/Aug/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Timothy Baldridge
Resolution: Completed Votes: 1
Labels: None


 Description   

Probably because of intermediate locals generated by SSA form, valid set! expressions get converted into set! on locals. I was trying to set the 'innerHTML' property of a HTML element stored in a top level var in a go block when I encountered this.



 Comments   
Comment by Timothy Baldridge [ 09/Aug/13 4:14 PM ]

fixed in https://github.com/clojure/core.async/commit/018d26a0faf40f48d7b95c23777224deef91a126





[ASYNC-17] Loop bindings cant's see prior bindings made in the same loop when the loop is in a go block Created: 08/Aug/13  Updated: 09/Aug/13  Resolved: 09/Aug/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Kevin Marolt Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None


 Description   

Loop bindings cant's see prior bindings made in
the same loop when the loop is in a go block:

(require '[clojure.core.async :refer [go]])
(go (loop [x 41 y (inc x)] (println y)))

Rather than printing 42, it either complains that x can't be
resolved in that context (in Clojure), or that x ist an undeclared
Var (in ClojureScript).



 Comments   
Comment by Timothy Baldridge [ 08/Aug/13 9:54 AM ]

Confirmed as a bug, loop bindings happen in parallel in the current code. This should be changed to match normal CLJ semantics.

Comment by Timothy Baldridge [ 09/Aug/13 4:16 PM ]

fixed in https://github.com/clojure/core.async/commit/d445dd3d6a231f52989f45021f58a5a1413cee17





[ASYNC-14] Possible incorrect behavior on apply >! within go block Created: 28/Jul/13  Updated: 16/Aug/13  Resolved: 16/Aug/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jeff Sigmon Assignee: Timothy Baldridge
Resolution: Declined Votes: 0
Labels: None
Environment:

Java 1.7.0_15 Java HotSpot(TM) 64-Bit Server VM
clojure 1.5.1
core.async 0.1.0-SNAPSHOT



 Description   

Below is code taken form the example file at https://github.com/clojure/core.async/blob/master/examples/walkthrough.clj

(let [c (chan)]
  (go (>! c "hello"))
    (assert (= "hello" (<!! (go (<! c)))))
    (close! c)))

I get different behavior when I change the first go block above to apply the >! function. In this case the execution hangs on the second go block. An example is below:

(let [c (chan)]
  (go (apply >! [c "hello"]))
    (assert (= "hello" (<!! (go (<! c)))))
    (close! c)))


 Comments   
Comment by Jeff Sigmon [ 28/Jul/13 9:35 AM ]

Sorry about the misleading indentation in the code above...

Comment by Ghadi Shayban [ 28/Jul/13 10:59 PM ]

<! and >! are not normal IFn's or applicative function calls. They are akin to special forms or value-less macros compiled by the go macro. Maybe we can improve the docstring to show that those forms can't be applied across its arguments.

>! macro docstring:

puts a val into port. nil values are not allowed. Must be called inside a (go ...) block. Will park if no buffer space is available.

The >! var in clojure.core.async is just a hook to attach some docstring metadata. Its state can be nil and the go macro would still work the same.

Comment by Timothy Baldridge [ 16/Aug/13 7:24 AM ]

<! and >! are not functions, they are go macro special forms. They should be treated as macros. This is not a feature we plan to implement.

Comment by Timothy Baldridge [ 16/Aug/13 7:25 AM ]

If you need behavior like you show above, consider using a destructuring let/loop/fn





[ASYNC-18] CompilerException attempting to perform a transaction inside go block Created: 15/Aug/13  Updated: 16/Aug/13  Resolved: 16/Aug/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Adam Wittenberg Assignee: Timothy Baldridge
Resolution: Declined Votes: 0
Labels: bug


 Description   

When setting up a transaction inside of a go block, receiving the following error:

CompilerException java.lang.RuntimeException: No such var: clojure.core/runInTransaction, compiling:(NO_SOURCE_PATH:2:8)

(require '[clojure.core.async :as async :refer :all])

(def bar (ref []))
(def c (chan))

(defn foo []
(<!! (go (dosync
(doseq [i (range 10)]
(alter bar conj (<! c)))))))



 Comments   
Comment by Timothy Baldridge [ 16/Aug/13 9:08 AM ]

There are two problems with the example given.

a) dosync wraps the body of the body of the transaction in a fn. Go block translation stops at fn boundaries. The same applies to doseq.

b) The bigger problem is that this example code is incorrect. A transaction body may executed multiple times in that case some messages received from the channel may be dropped.

Closing this issue as the examples are flawed. However I will recommend that you look into doing the takes outside of the transaction, and then using a function to execute the transaction outside the body of a go.





[ASYNC-19] Exceptions hang return channel of go blocks Created: 19/Aug/13  Updated: 19/Aug/13  Resolved: 19/Aug/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Brian Kirkbride Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None


 Description   

If the body of a (go) block throws an exception, the return channel hangs forever. It is unclear whether this is intended behavior or not. The behavior of (thread) blocks differs and is what I would have expected.

For example:

(<!! (go (/ 1 0)))
; hangs forever
(<!! (thread (/ 1 0)))
; returns nil immediately

Closing the channel is definitely more convenient. It's arguable that the caller is responsible for choosing their own failure semantics, but it should probably be consistent between (thread) and (go).

Would it make sense to wrap `body` with `(try ~@body (catch Throwable t# nil))` inside of the (go) macro?



 Comments   
Comment by Timothy Baldridge [ 19/Aug/13 4:33 PM ]

Fixed in https://github.com/clojure/core.async/commit/5f1d08a390a460b0408563c3118a82a81b3fd083





[ASYNC-2] incorrect behavior in CLJS when using <! in loop/recur binding Created: 11/Jul/13  Updated: 27/Sep/13  Resolved: 27/Sep/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Timothy Baldridge
Resolution: Declined Votes: 0
Labels: None


 Description   
(loop [x (<! c)]
   ...)

does not work correctly, you will get nil values on some reads off this channel, you have to write

(loop []
  (let [x (<! c)]
    ...))

in order to only get nil when the channel closes.



 Comments   
Comment by Alexander Redington [ 12/Jul/13 10:48 AM ]

David Nolen I have tried to reproduce on https://github.com/aredington/core.async/blob/ASYNC-2-TEST/src/test/clojure/clojure/core/async/ioc_macros_test.clj#L191 but cannot generate failures. Is there a way to adjust the test to more reliably provoke failure?

Comment by David Nolen [ 26/Jul/13 9:27 AM ]

Sorry I should have been more specific this appears to affect ClojureScript core.async not Clojure.

Comment by Timothy Baldridge [ 27/Sep/13 8:21 AM ]

Can't reproduce





[ASYNC-20] Case macro in go block ignores default expression Created: 20/Aug/13  Updated: 27/Sep/13  Resolved: 27/Sep/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Leon Grapenthin Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: bug, go
Environment:

Clojure 1.5.1 in the JVM, core.async-0.1.0-20130819.220150-69



 Description   

To reproduce the error use this code:
(go (case true
false false
nil))

An IllegalArgumentException will be thrown (as if there was no default expression).
Exception in thread "async-dispatch-46" java.lang.IllegalArgumentException: No matching clause: true



 Comments   
Comment by Timothy Baldridge [ 27/Sep/13 8:34 AM ]

fixed in: https://github.com/clojure/core.async/commit/f9b24552cf4f6b8b86f3377c7b7a42a618a9fd76





[ASYNC-26] putting on a mult with no chans tapped breaks the mult badly Created: 07/Oct/13  Updated: 31/Oct/13  Resolved: 31/Oct/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Leon Grapenthin Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None


 Description   

This is happening because of
;;wait for all
(<! dchan)

(https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async.clj#L664)

With no channels in the mult the helper function done will never be invoked and the mult will never work again.
If this is intended behaviour an exception would be nice.



 Comments   
Comment by Timothy Baldridge [ 31/Oct/13 9:19 AM ]

Fixed in: https://github.com/clojure/core.async/commit/3f98058f168a5e0bec67e662fadc5c13c97b1500#diff-5c087e8e400be45f4d03e0a618ef9d46





[ASYNC-24] dosync does not work inside go macro Created: 15/Sep/13  Updated: 31/Oct/13  Resolved: 31/Oct/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Michael Ummels Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: bug,, go
Environment:

Clojure 1.5.1 in the JVM, core.async-0.1.0-20130827.050117-78"



 Description   

The following code results in an exception:

=> (go (dosync nil))

CompilerException java.lang.RuntimeException: No such var: clojure.core/runInTransaction



 Comments   
Comment by Michael Ummels [ 09/Oct/13 2:05 AM ]

Fixed in master. Please close.

Comment by Timothy Baldridge [ 31/Oct/13 9:20 AM ]

Fixed in master





[ASYNC-33] core.async needs to be updated for 0.0-2024 Created: 08/Nov/13  Updated: 08/Nov/13  Resolved: 08/Nov/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None


 Description   

ClojureScript has changed in a few important way behind the scenes and core.async taps into some of these details. Currently when building the test core.async stackoverflows.



 Comments   
Comment by David Nolen [ 08/Nov/13 2:04 PM ]

I poked around a bit Timothy but I don't see anything obvious and I don't know the internals quite well enough to understand why this would be. At first I thought I might have borked macros in some way, but ClojureScript builds just fine and core.match also seems unaffected.

Comment by David Nolen [ 08/Nov/13 5:08 PM ]

I sorted this out, this was because of the inlining macros for data structures, core.async convert these to function calls which just get inlined again creating a loop, fixed the inlining macros to emit constructor calls instead of literals.





[ASYNC-30] Broken namespace reference in async.cljs Created: 31/Oct/13  Updated: 10/Nov/13  Resolved: 10/Nov/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Colin Jones Assignee: Rich Hickey
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File cljs_core_ns.patch    

 Description   

On master currently:

WARNING: No such namespace: core at line 524 public/javascript/cljs/core/async.cljs

I'm not too savvy on the cljs internals, but this definitely seems to break our project's use of core.async with the latest core.async release (which we went to in order to try and get up to the latest cljs release).



 Comments   
Comment by Ghadi Shayban [ 10/Nov/13 12:16 PM ]

Fixed as of 1bf8cf4d528ede5 on Nov 1





[ASYNC-44] property access syntax within go blocks is broken Created: 08/Dec/13  Updated: 10/Dec/13  Resolved: 10/Dec/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Travis Vachon Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File async_44.patch     Text File property-access.patch    
Patch: Code and Test

 Description   

`(.-foo x)` is being compiled into `x._foo()` inside a go block.

Patch here:

https://github.com/clojure/core.async/pull/41



 Comments   
Comment by Travis Vachon [ 10/Dec/13 9:54 AM ]

add git am able patch

Comment by Timothy Baldridge [ 10/Dec/13 5:52 PM ]

fixed in master.





[ASYNC-47] It is odd that the thread macro does not maintain per-thread bindings, the way the go macro does Created: 10/Dec/13  Updated: 12/Dec/13  Resolved: 12/Dec/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Howard Lewis Ship Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None


 Description   

As stated, it is odd that thread and go are dissimilar in this way; if there's a rationale for it, I'd prefer to see it documented; otherwise, it would be nice to see thread do what go does.



 Comments   
Comment by Timothy Baldridge [ 12/Dec/13 9:36 PM ]

You're right, it is. I'll get it fixed ASAP.

Comment by Timothy Baldridge [ 12/Dec/13 10:28 PM ]

Fixed in master





[ASYNC-56] Pubs fail (in CLJS only) if there are no subscribers for a topic Created: 19/Feb/14  Updated: 19/Feb/14  Resolved: 19/Feb/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jonas Enlund Assignee: Rich Hickey
Resolution: Completed Votes: 0
Labels: None


 Description   

The following code throws "Uncaught Error: No protocol method Mux.muxch* defined for type null":

(def c (async/chan))
(def p (async/pub c :topic))
(async/put! c {:topic :foo})

If a sub is registered for the :foo topic everything works as expected. I suspect the reason is that this line is missing from the CLJS source.



 Comments   
Comment by David Nolen [ 19/Feb/14 8:23 AM ]

fixed https://github.com/clojure/core.async/commit/ca148ebf812576b9eaa777adac6927ac22349a62





[ASYNC-52] Go block run by multiple threads at the same time for a single chan instance Created: 29/Jan/14  Updated: 20/Apr/14  Resolved: 20/Apr/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Gerrit Jansen van Vuuren Assignee: Rich Hickey
Resolution: Not Reproducible Votes: 0
Labels: None


 Description   

I'm using channels instead of agents to provide serial access to resources.
The logic is: (ch is buffered)
go loop:
f = read ch
(f)

f is a function that in my test case writes to a output stream, sometimes f will close the output stream, and recreate a new one. The output stream is held in a shared atom. If the go block takes one value after another everything should run fine. The thing is I get an output stream closed exception. After several runs it 'seems' to me that the go block is run by different threads at the same time.

If I change the go block to a thread the error goes away.

To reproduce the error:
clone https://github.com/gerritjvv/fun-utils

and run in leiningen

(use 'fun-utils.chtest)
(test-star)

The file is https://github.com/gerritjvv/fun-utils/blob/master/src/fun_utils/chtest.clj

The go block is on line 24.



 Comments   
Comment by Gerrit Jansen van Vuuren [ 29/Jan/14 5:49 PM ]

please ignore and close this.
I've found the cause: I was creating a new channel on every write .





[ASYNC-60] close! should deblock putting operations like >!! Created: 23/Mar/14  Updated: 09/May/14  Resolved: 09/May/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Alexander Kauer Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None
Environment:

[org.clojure/clojure "1.5.1"]
[org.clojure/core.async "0.1.278.0-76b25b-alpha"]



 Description   

When closing a full or bufferless channel then currently blocked insertions should be deblocked and treated as if they tried to insert the value into a closed channel in the first place. Currently the putting operation blocks forever.

Example:

(defn -main
"I don't do a whole lot ... yet."
[& args]
(let [ch (chan)]
(thread
(Thread/sleep 1000)
(close! ch)
(println "channel closed"))
(>!! ch 42)
(println "never reached")))

Yields only "channel closed" and keeps blocked forever.



 Comments   
Comment by Alexander Kauer [ 27/Mar/14 5:22 PM ]

Duplicate of Issue ASYNC-36

Comment by Timothy Baldridge [ 09/May/14 11:25 AM ]

this is a duplicate, but I added a note to the close! doc string to explain the semantics better.





[ASYNC-8] Add constrained read/write-only ports Created: 15/Jul/13  Updated: 09/May/14  Resolved: 09/May/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Brandon Bloom Assignee: Timothy Baldridge
Resolution: Declined Votes: 0
Labels: None


 Description   

Proof of concept patch here:

https://github.com/clojure/core.async/pull/20/files

As discussed in IRC, this adds support for read-only and write-only "ports", which are constrained wrappers around channels. Write-only ports allow both put and close operations, were as read-only ports allow only take operations. Unsupported operations throw.

I'm open to suggestions for better names than <port and >port.



 Comments   
Comment by Timothy Baldridge [ 09/May/14 11:28 AM ]

Do we do not have plans to implement this at this time, however, impl/ReadPort and impl/WritePort could accomplish this if needed. These interfaces are still considered "alpha" and may change, but if you need to write your own port< feel free to do so and maintain it in your project.





[ASYNC-21] CLJS -> ioc-macros/fixup-aliasses throws exception Created: 02/Sep/13  Updated: 09/May/14  Resolved: 09/May/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Creighton Kirkendall Assignee: Timothy Baldridge
Resolution: Declined Votes: 0
Labels: None

Attachments: Text File 0001-added-a-check-to-fixup-aliases-for-namespace-to-stop.patch    
Patch: Code

 Description   

Under certain circumstances I get the following exception when using a 'go' block.

Caused by: java.lang.ClassCastException: clojure.lang.Namespace cannot be cast to clojure.lang.Named
             core.clj:1505 clojure.core/name
        ioc_macros.clj:613 cljs.core.async.impl.ioc-macros/fixup-aliases
        ioc_macros.clj:625 cljs.core.async.impl.ioc-macros/eval4971[fn]
        ioc_macros.clj:110 cljs.core.async.impl.ioc-macros/all[fn]

This is caused by the calling (name ns) where ns is namespace instead of calling (ns-name) first. The exception is thrown by the 'go' block in 'basic-test' here: https://gist.github.com/ckirkendall/6415293



 Comments   
Comment by Ghadi Shayban [ 18/Nov/13 11:12 PM ]

Creighton, do you still encounter the issue against release 0.1.256.0-1bf8cf-alpha?

Comment by Timothy Baldridge [ 09/May/14 11:29 AM ]

Closed due to no further information.





[ASYNC-48] Recur fails within catch Created: 21/Dec/13  Updated: 09/May/14  Resolved: 09/May/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Gerrit Jansen van Vuuren Assignee: Timothy Baldridge
Resolution: Declined Votes: 0
Labels: bug


 Description   

This is related to
http://dev.clojure.org/jira/browse/ASYNC-7

Having a loop in a go block and the recur inside a catch statement causes an IllegalArgumentException.

The code is:

(go
(loop [i 0]
(try
(do
(+ 1 1))
(catch Exception e (do
(prn e)
(recur (inc i)))))))

;; IllegalArgumentException No implementation of method: :emit-instruction of protocol: #'clojure.core.async.impl.ioc-
;; macros/IEmittableInstruction found for class: clojure.core.async.impl.ioc_macros.Jmp clojure.core/-cache-protocol-fn
;;(core_deftype.clj:541)



 Comments   
Comment by Leon Grapenthin [ 25/Dec/13 9:14 AM ]

This doesn't work outside of a go block either.

Comment by Timothy Baldridge [ 09/May/14 11:30 AM ]

Closing due to example not being valid code.





[ASYNC-25] Dependency on clojurescript is introduced into clojure only projects Created: 05/Oct/13  Updated: 23/Jun/14  Resolved: 23/Jun/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Hugo Duncan Assignee: Unassigned
Resolution: Not Reproducible Votes: 0
Labels: None


 Description   

When using core.async in a clojure only project, a dependency on Clojurescript is introduced.

Consider making the clojurescript dependency have "provided" scope, or moving it to a :dev profile.



 Comments   
Comment by Alex Miller [ 23/Jun/14 10:05 AM ]

Looks like this was already done - seems to be marked provided in pom and does not show up as transitive dependency in using project.





[ASYNC-62] recur across try possible, leaks ExceptionFrames Created: 27/Mar/14  Updated: 23/Jun/14  Resolved: 23/Jun/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Philip Lewis Assignee: Unassigned
Resolution: Not Reproducible Votes: 0
Labels: None
Environment:

[org.clojure/clojure "1.5.1"]
[org.clojure/core.async "0.1.278.0-76b25b-alpha"]



 Description   

This shouldn't compile, but it does and generates nested ExceptionFrames until it crashes:

(go-loop [] (try (if 1 (recur))))

Without the if, it throws java.lang.IllegalArgumentException: No implementation of method: :emit-instruction of protocol: #'clojure.core.async.impl.ioc-macros/IEmittableInstruction found for class: clojure.core.async.impl.ioc_macros.Jmp.

Outside of a go block it throws an UnsupportedOperationException (either "can only recur from tail" or "cannot recur across try").



 Comments   
Comment by Alex Miller [ 23/Jun/14 10:59 AM ]

On latest CLJ version (0.1.303.0-886421-alpha), I see "java.lang.UnsupportedOperationException: Can only recur from tail position" from this code.





[ASYNC-28] try/catch inside go block may cause a reflection warning - 0.1.222.0-83d0c2-alpha Created: 08/Oct/13  Updated: 23/Jun/14  Resolved: 23/Jun/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Howard Lewis Ship Assignee: Unassigned
Resolution: Not Reproducible Votes: 0
Labels: None


 Description   

I have this code:

(go
  (try
     ...
    (catch Throwable t
          (l/errorf t "Acceptor %s exception: %s" channel-key (.getMessage t))
          (ctx/trigger-error-handlers t))))

I get a reflection warning: reference to field getMessage can't be resolved.

This does not occur if the same code is moved outside the go block.

My assumption is that an implicit type hint (t is of type Throwable) is lost in the process of converting the block to a state machine.

Adding an explicit type hint does not fix the problem.

Further, the warning is associated with the line containing the go symbol, not the catch symbol. See ASYNC-27.



 Comments   
Comment by Alex Miller [ 23/Jun/14 11:04 AM ]

I tried this on the latest (0.1.303.0-886421-alpha) and saw no reflection warnings.

(require '[clojure.core.async :refer (go)])
(set! *warn-on-reflection* true)
(go 
  (try 1 
    (catch Throwable t (println "Got ex: " (.getMessage t)))))

If you still see this, please provide an example that is reproducible, thanks!





[ASYNC-75] alts!! not working on a channel which is subscribed to a pub-channel Created: 23/Jun/14  Updated: 24/Jun/14  Resolved: 24/Jun/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Daniel Ziltener Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

Clojure 1.6.0, core.async 0.1.303.0-886421-alpha



 Description   

Error message: Exception in thread "main" java.lang.UnsupportedOperationException: count not supported on this type: ManyToManyChannel

Minimal failing case:

(require '[clojure.core.async :refer (chan pub sub put! alts!!)])
(def out (chan))
(def publisher (pub out #(:topic %)))
(def s (chan))
(sub publisher :1 s)

(put! out {:topic :1 :content "Yes!"})
(alts!! s :default "Oh no.")


 Comments   
Comment by Alex Miller [ 24/Jun/14 6:51 AM ]

Your use of alts!! has a bug - the ports passed to it is expected to be a vector, not a single operation:

(alts!! [s] :default "Oh no.")





[ASYNC-76] Exceptions cannot be captured by default uncaught exception handler Created: 02/Jul/14  Updated: 06/Aug/14  Resolved: 06/Aug/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Stuart Sierra Assignee: Stuart Sierra
Resolution: Completed Votes: 6
Labels: None

Attachments: Text File 0001-ASYNC-76-do-not-catch-exceptions-on-thread-pool.patch     Text File 0002-ASYNC-76-propagate-exceptions-with-tests.patch    
Patch: Code and Test
Approval: Ok

 Description   

Both core.async thread pools have a try/catch which catches and prints exceptions thrown in callbacks. This prevents application code from using the built-in mechanisms of the JVM to handle exceptions on arbitrary threads, namely Thread.setDefaultUncaughtExceptionHandler

In addition, the pool for 'thread' and 'thread-call' does not close the channel when an exception is thrown, which may lead to deadlocks.

Current Patch: 0002-ASYNC-76-propagate-exceptions-with-tests.patch

Approach: For the callback/go thread pool, do not catch exceptions at all. For the 'thread' pool, remove the 'catch' and close the channel in a 'finally'.

Background: Printing exceptions was added shortly after changing the arity to the 'put!' callback, to aid in debugging, see commit 9fcae995. Prior to this, the 'thread-call' function has always dropped exceptions silently; see commit 0b8e6171.

Duplicate of ASYNC-71 and similar to ASYNC-61, both of which request that the thread pools dispatch errors to a handler function Var which application code can alter.

An earlier issue (no JIRA ticket) occurred when tasks were submitted to the ThreadPoolExecutor with .submit, which returns a Future, instead of .execute.



 Comments   
Comment by Timothy Baldridge [ 03/Jul/14 8:13 AM ]

These threads are created in a fixed size thread pool. Won't you need to set the exception handler on the Executor constructor instead of on the thread itself?

Comment by Stuart Sierra [ 03/Jul/14 8:18 AM ]

No, the default uncaught exception handler is global for the whole JVM. Thread.setDefaultUncaughtExceptionHandler is static.

The exception handler can be overridden on a per-thread or per-thread-group basis.

Comment by Alex Miller [ 06/Aug/14 10:23 AM ]

applied to master





[ASYNC-80] Fix documentation (or code) - related to "transformer" and deprecated counterparts Created: 28/Jul/14  Updated: 07/Aug/14  Resolved: 07/Aug/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Major
Reporter: Max Penet Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

When looking at the documentation now there are a bunch of functions marked as deprecated with the following message:
"Deprecated - this function will be removed. Use transformer instead"

However the `transformer` doesn't exist yet in the currently released version, or master for that matter...
It would be welcome to fix the doc for those who are using the various transformer functions already, even if they are deprecated.






[ASYNC-84] Issue with (require [clojure.core.async :as async]) Created: 08/Aug/14  Updated: 02/Sep/14  Resolved: 02/Sep/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Adam Krieg Assignee: Unassigned
Resolution: Not Reproducible Votes: 0
Labels: None


 Description   

I was attempting to try out the new transducer stuff with core.async, but was thwarted by namespace issues.

(ns my-ns
(require [clojure.core.async :as async]))

Yields:

java.lang.IllegalArgumentException: No single method: add_BANG_STAR of interface: clojure.core.async.impl.protocols.Buffer found for function: add!* of protocol: Buffer

My dependencies are as follows:

<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>1.7.0-alpha1</version>
</dependency>

<dependency>
<groupId>org.clojure</groupId>
<artifactId>core.async</artifactId>
<version>0.1.319.0-6b1aca-alpha</version>
</dependency>



 Comments   
Comment by Ghadi Shayban [ 11/Aug/14 11:30 PM ]

This sounds like a code reloading issue. Have you tried removing your target/ directory and restarting the REPL?

Totally unrelated, but ns declarations take keyword :require instead of symbol.

Comment by Alex Miller [ 02/Sep/14 9:41 AM ]

Can't reproduce





[ASYNC-72] CLJS: mult becomes blocked after putting to a closed channel Created: 15/May/14  Updated: 14/Oct/14  Resolved: 14/Oct/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Logan Linn Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File cljs_mult_dec.patch    
Patch: Code

 Description   

A mult can become blocked after a putting to a closed tap channel due to an off-by-one error in triggering the end condition.

It appears the issue was recently fixed in the Clojure version of mult, but not the ClojureScript version.
https://github.com/clojure/core.async/commit/8864214ed9fa9aa8dc12297c6cf99ad0be65a6ae

The issue occurs because the counter that indicates the mult has finished a putting to all taps, dctr is decremented out of band and the zero? triggering condition in done function is missed.
https://github.com/clojure/core.async/blob/65b2d6c81350ba8b4bb3a8b82ad45ba984c0037c/src/main/clojure/cljs/core/async.cljs#L457

The done function passed to put! appears to be called regardless of whether the channel is closed. Because of this, we don't need to (swap! dctr dec) or necessarily call (done nil) (the CLJ fix) to fix this issue.

Demonstration: https://gist.github.com/loganlinn/e840139a9ab5503970fd



 Comments   
Comment by Gijs Stuurman [ 06/Jun/14 11:03 AM ]

The title of this issue says it's CLJS only, but the double done/counter-decrement applies to the CLJ version as well. As is briefly mentioned at the end of this issue.

For closed channels the done function is called twice in mult, because put! returns false for closed channels and calls the callback:
https://github.com/clojure/core.async/blob/65b2d6c81350ba8b4bb3a8b82ad45ba984c0037c/src/main/clojure/clojure/core/async.clj#L684

In the CLJ version this will not lead to blocking but it violates the behavior in the docstring of "each tap must accept before the next item is distributed" when a tap is closed.

Comment by David Nolen [ 14/Oct/14 6:09 AM ]

As far as I can tell the original issue has been fixed in master?

Comment by Logan Linn [ 14/Oct/14 12:02 PM ]

Yeah. It appears https://github.com/clojure/core.async/commit/40ab7edacac747af1108c80223039e8a0b1c2ca9 resolved the issue. Thanks!





[ASYNC-68] Improve error handling for map< and map> Created: 09/May/14  Updated: 04/Nov/14  Resolved: 04/Nov/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Timothy Baldridge Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Approval: Vetted

 Description   

How can we deal with error handling better. For example, map< will throw an exception in the taker's thread if the function throws an exception. map> throws an exception on the put!. So this can crash an entire chain of ops. For example a pipe into map> will crash the pipe go to crash if the map function throws an error. We can add try/catch to all of this, but what do we do with the exceptions, and how do we recover?



 Comments   
Comment by Timothy Baldridge [ 14/May/14 12:25 PM ]

<Comment Removed> I misunderstood. But the original problem still stands.

Comment by Alex Miller [ 04/Nov/14 4:08 PM ]

Won't fix - these are deprecated and going away.





[ASYNC-101] clojure.core.async/reduce doesn't respect reduced Created: 04/Nov/14  Updated: 23/Feb/15  Resolved: 23/Feb/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Alex Miller Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File async-101.patch    
Patch: Code and Test
Approval: Ok

 Description   

clojure.core.async/reduce does not currently look for or check whether the result of f is reduced.

Patch: async-101.patch



 Comments   
Comment by Fogus [ 09/Jan/15 1:27 PM ]

Works as expected and is a clean impl.

Comment by Alex Miller [ 23/Feb/15 8:30 AM ]

Applied patch.





[ASYNC-104] offer! and poll! Created: 10/Nov/14  Updated: 23/Feb/15  Resolved: 23/Feb/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Stuart Halloway Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File async-104.patch    
Patch: Code and Test
Approval: Ok

 Description   

offer! and poll! facilitate subsystems that continue to progress even when their channel partners are not keeping up. This functionality could be done today as a wrapper on alts!!, but can be done more efficiently at the channel level.

  • never blocks
    • usable in all contexts
  • performs a channel operation if possible to do so immediately
    • returns value or nil for poll!
    • returns true or false for offer!
  • initial implementation could use alt!! plus a default
    • this is inefficient
  • better implementation would work directly on channels
    • API that provides a new exit point when enqueue attempt fails


 Comments   
Comment by Alex Miller [ 11/Nov/14 5:00 PM ]

Added offer! and poll! to api per specs above. They call through impl/put! and impl/take! just like >!! and <!!, however I added a new function to the handler protocol: blockable? that is true for all prior handlers (meaning that it is ok for the channel to block them and respond later).

The offer! and poll! calls pass handlers with blockable?=false and do not use a promise. Instead they expect to always receive the value as the result of the impl/put! or impl/take! call.

Inside the channel, the only change made is that when blockable? is false, the put or take is not queued and nil is returned instead. All other cases where the operation can succeed, still succeed.

Because offer! and poll! never block, they are usable both in and out of go blocks. There are tests for both.

The patch does not include the CLJS-equivalent changes.

Comment by Fogus [ 09/Jan/15 4:02 PM ]

Read, tested, REPL'd and understood. This patch looks good to my eyes.

Comment by Alex Miller [ 23/Feb/15 8:59 AM ]

Applied patch





[ASYNC-86] Update tools.analyzer.jvm dep Created: 14/Aug/14  Updated: 30/Mar/15  Resolved: 30/Mar/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Completed Votes: 4
Labels: None

Attachments: Text File 0001-update-to-tools.analyzer.jvm-0.6.6.patch    
Patch: Code
Approval: Ok
Waiting On: Timothy Baldridge

 Comments   
Comment by Nicola Mometto [ 18/Aug/14 1:17 PM ]

This patch also adds a bunch of :op nodes that -item-to-ssa might hit but were not implemented, such as :set! and :host-interop
It also improves/simplifies the passes done by core.async by using info already collected by t.a.jvm passes

Comment by Darrick Wiebe [ 22/Aug/14 7:27 PM ]

The old version of tools.analyzer.jvm seems to be causing a problem with the lein-figwheel plugin if I update it to the current version of core.async.

I've reported that at https://github.com/bhauman/lein-figwheel/issues/32 and am unsure if an update to this dependency would fix the issue, but thought I should point it out here.

Comment by Nicola Mometto [ 22/Aug/14 8:23 PM ]

No, this is not related to core.async.
tools.analyzer.jvm depends on core.cache and if a leiningen plugin pulls an older version of core.cache, than plugins that depend tools.analyzer.jvm will not work, assuming they are :eval-in-leiningen true

Comment by Ambrose Bonnaire-Sergeant [ 12/Oct/14 12:50 PM ]

This issue is stopping core.typed from upgrading past tools.analyzer.jvm 0.3.0.

Comment by Andy Fingerhut [ 12/Oct/14 4:33 PM ]

Ambrose, this comment is directed to you, with no intended bearing on this ticket ASYNC-86.

Just an FYI regarding core.typed that I have found it not exactly fun, but it has eliminated some problems by having Eastwood copy the source code of tools.analyzer(.jvm) and its dependencies, with renamed namespaces, into its own source tree. This enables Eastwood to analyze+eval source code of any version of those libraries without causing conflicts. I have a pre-alpha version of a tool to assist in automating parts of this copy&rename called Dolly [1]. If Dolly was polished some more, it might become useful to you for this purpose in core.typed.

Benedek Fazekas has created a tools called MrAnderson [2] for the same purpose (independently developed from Dolly). I haven't looked into the details of how it works yet, but it may do a better job than Dolly 0.1.0.

[1] https://github.com/jafingerhut/dolly for the library, https://github.com/jonase/eastwood/blob/master/copy-deps-scripts/README.md#using-dolly-to-copy-dependencies-into-eastwood-source-code for copy-and-paste-into-a-REPL forms that I use to copy in updated versions of Eastwood dependencies into its source tree. The polishing I mention above would cut that down significantly.

[2] https://github.com/benedekfazekas/mranderson I learned about this lib from a Github issue on Eastwood, where there is a little bit of discussion: https://github.com/jonase/eastwood/issues/87

Comment by Nicola Mometto [ 15/Oct/14 12:35 PM ]

Added patch to update to tools.analyzer.jvm 0.6.1.
This makes the core.async passes use the new tools.analyzer pass scheduler and the :passes-opts mechanism to configure the passes.

Comment by Timothy Baldridge [ 27/Oct/14 9:17 AM ]

Took a look at the latest patch, it applies cleanly and the tests all pass. Marking it as screened.

Comment by Nicola Mometto [ 27/Oct/14 11:18 AM ]

Updated patch to use version 0.6.3 of t.a.jvm which has a faster scheduler and significant performance enhancements

Comment by Alex Miller [ 30/Oct/14 3:56 PM ]

Tim, can you re-screen latest?

Comment by Nicola Mometto [ 03/Nov/14 1:59 PM ]

Attached another patch updating to the recently released t.a.jvm 0.6.4, identical to the previous patch except for the dependency.

Comment by Nicola Mometto [ 10/Nov/14 3:08 PM ]

Updated lastest patch adding a -item-to-ssa impl for :with-meta nodes, discussed with Tim Baldridge on irc

Comment by Timothy Baldridge [ 27/Feb/15 3:13 PM ]

Screened, looks good.





[ASYNC-120] cljs port of promise-chan|buffer / offer! / poll! Created: 15/Mar/15  Updated: 03/Apr/15  Resolved: 03/Apr/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Major
Reporter: Max Penet Assignee: David Nolen
Resolution: Completed Votes: 1
Labels: None

Attachments: File promise-chan+offerpoll-cljs.diff    

 Description   

Giving a try on this, but I am not really familiar with cljs anymore. It seems fairly straightforward. I would add tests but I am still trying to figure out how to run the current cljs tests at this point.



 Comments   
Comment by Max Penet [ 16/Mar/15 5:16 AM ]

fixed fn-handler calls in offer/poll

Comment by Max Penet [ 16/Mar/15 7:19 AM ]

latest version, with passing tests

Comment by David Nolen [ 17/Mar/15 3:16 PM ]

Will review, thanks.

Comment by David Nolen [ 03/Apr/15 7:08 PM ]

fixed by

https://github.com/clojure/core.async/commit/1afb09d766cce8cfc386d3204bed6f32b483472b
https://github.com/clojure/core.async/commit/d8047c0b0ec13788c1092f579f03733ee635c493





[ASYNC-23] Support channel buffers of unlimited size Created: 10/Sep/13  Updated: 29/Jun/15  Resolved: 15/Sep/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Constantine Vetoshev Assignee: Timothy Baldridge
Resolution: Declined Votes: 0
Labels: None
Environment:

Clojure
ClojureScript


Attachments: Text File 0001-Add-unlimited-size-buffer-implementation.patch    
Patch: Code and Test

 Description   

It is sometimes useful to use buffered async channels and not worry about either pre-allocating their size, or the way sliding and dropping buffers can lose potentially critical data passing through the channel.

The attached patch adds support for clojure.core.async/unlimited-buffer and cljs.core.async/unlimited-buffer for this purpose.



 Comments   
Comment by Timothy Baldridge [ 15/Sep/13 3:55 PM ]

One of the key aspects of core.async is that back-pressure and sliding/dropping buffers allow for decoupling of processes. A unbounded queue introduces many problems. Now a incorrectly designed system can crash, but not for some time. With the other buffer types a bug in the system will either a) allow producers to continue, or b) backup the producers allowing for easier debugging.

This patch doesn't really fit with CSP theory. And one of the main goals of core.async is to make users recognize where there are unbounded buffers, and allow them to remove them. Closing as this doesn't fit with the goals of the library.

Comment by Daniel Compton [ 29/Jun/15 4:38 PM ]

While I agree with Tim that this doesn't fit the goals of core.async, from a quick read through the patch, I don't think theres anything stopping you from creating this as a library (with proper warnings about the implications of using unbounded queues).





[ASYNC-43] queue-dispatcher should fall back to process.nextTick if setImmediate is not available Created: 07/Dec/13  Updated: 07/Aug/15  Resolved: 07/Aug/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Travis Vachon Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: cljs

Attachments: Text File async_43.patch     Text File nextTick.patch    
Approval: Triaged

 Description   

discussion here:

https://groups.google.com/forum/#!searchin/clojurescript/nextTick/clojurescript/RW1FMv0UoPE/hsMHI4SLKXYJ

discussion of the differences between setImmediate and nextTick here:

http://stackoverflow.com/questions/15349733/setimmediate-vs-nexttick

it sounds to me like nextTick should be ok, but I'm not familiar with the design decisions in the current implementation

I'm happy to create a patch - will do that shortly.



 Comments   
Comment by Travis Vachon [ 07/Dec/13 7:28 PM ]

patch here: https://github.com/clojure/core.async/pull/40

Comment by Travis Vachon [ 08/Dec/13 8:52 PM ]

just the code, not entirely sure how to test this, but have tested manually in the parse.com cloud code environment

Comment by Travis Vachon [ 10/Dec/13 9:53 AM ]

add git am able patch

Comment by Travis Vachon [ 05/Mar/14 5:21 PM ]

just want to ping this issue - anything else it needs to be mergable? I'm using a core.async fork at the moment and would love to get back on the main line!

Comment by David Nolen [ 05/Nov/14 6:24 AM ]

The patch probably needs updating - we've since switched to Google Closure for choosing the underlying dispatch functionality for the JavaScript environment.

Comment by David Nolen [ 07/Aug/15 2:10 PM ]

we use Google Closure to make this decision.





[ASYNC-147] subscriber blocks other subscriber of a topic Created: 24/Sep/15  Updated: 28/Sep/15  Resolved: 28/Sep/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Sonny To Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Here is code to reproduce the problem:

code
(require-macros '[cljs.core.async.macros :refer [go go-loop]])
(require '[cljs.core.async :refer [put! <! >! chan pub sub unsub]])

(defonce message-bus (chan))
(defonce message-publication (pub message-bus (fn [msg]
(if (vector? msg)
(first msg)
:no-topic))))

(def s1 (chan))
(def s2 (chan))

(sub message-publication :foo s1)
(go (while true (println "s1 " (<! s1))))
(put! message-bus [:foo "bar"]) ;works as expected

(sub message-publication :foo s2) ;blocks s1 from recieving messages
(put! message-bus [:foo "bar"]) ;s1 cannot recieve this message
(go (while true (println "s2 " (<! s2)))) ; unblocks s1; both s1 and s2 can recieve messages

code

This problem happens on both clojure and clojurescript



 Comments   
Comment by Alex Miller [ 28/Sep/15 12:30 PM ]

This is the expected behavior. Docstring for pub states:

"Each item is distributed to all subs in parallel and synchronously, i.e. each sub must accept before the next item is distributed. Use buffering/windowing to prevent slow subs from holding up the pub."

In this code, you are using an unbuffered channel as a sub and (according to the above), it will block delivery.





[ASYNC-103] promise-chan Created: 05/Nov/14  Updated: 28/Oct/15  Resolved: 28/Oct/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Stuart Halloway Assignee: Alex Miller
Resolution: Completed Votes: 3
Labels: None

Attachments: Text File async-103-2.patch     Text File async-103-3.patch     Text File async-103-4.patch     Text File async-103-5.patch     Text File async-103-6.patch     Text File async-103-cljs.patch     Text File async-103.patch    
Patch: Code and Test
Approval: Ok
Waiting On: Alex Miller

 Description   

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 a promise-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 buf

  • all 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 and promise-buffer.

Patch: async-103-6.patch, async-103-cljs.patch (catches up cljs to diffs in async-103-6)



 Comments   
Comment by Ghadi Shayban [ 07/Nov/14 4:06 PM ]

My initial gut reaction was that this is more related to semantics of the channel, not the buffer, and I'm wary of significant changes to esp. the impl protocols. But after seeing an impl, it looks straightforward and the changes aren't too significant. (Another possibility is to make another simpler implementation of a channel, with just slots for the value, lock and pending takers before the value is delivered. No slots for xfn or putters or buffer handling would be needed.)

Note an atom is not needed in the PromiseBuffer, just a set! on a mutable field to be inline with the other buffer flavors. If the patch continues using an atom, maybe guard val to not swap unnecessarily.

Comment by Alex Miller [ 07/Nov/14 11:09 PM ]

Good call on the atom - backed off to just using existing clojure.lang.Box. If that's too weird, will just deftype it.

Comment by Alex Miller [ 07/Nov/14 11:18 PM ]

Dur, just need the val field itself.

Comment by Fogus [ 09/Jan/15 4:27 PM ]

I'd really love to see the reason for the current impl over a more pointed promise channel (perhaps as described by Ghadi). This is a clear implementation, but with the addition of close-buf! some complexity is added for implementations in the future. Specifically, I'd like to at least see a dcostring in the protocol describing the meaning and desired semantics around close-buf! and what it should return and when. Like I said, this is a quality patch, but I'm just concerned that there are unstated assumptions around close-buf! that escape me.

Comment by Alex Miller [ 28/Jan/15 12:43 PM ]

Fogus, I looked into implementing the promise-chan a bit today but it requires replicating a significant portion of the existing chan implementation. I believe that's the primary reason to do it this way, just leveraging the majority chan code.

New -5 patch has two changes - I commented the Buffer protocol fns, and I removed promise-buffer from the api, as I think users should only use promise-chan.

Comment by Fogus [ 30/Jan/15 10:06 AM ]

The patch looks good. My only (minor) reservation is that the Buffer docstrings are written under the assumption that people will use instances only in the context of a guarded channel. I understand why of course, so I think I might be too pedantic here. Because of this I see no reason not to +1 this patch.

Comment by Alex Miller [ 23/Feb/15 8:32 AM ]

Applied patch.

Comment by Alex Miller [ 03/Apr/15 3:57 PM ]

Reopening (and likely reverting commit).

This example demonstrates that only one of the waiting blocks will be notified, instead of all, as we'd like:

(let [c (promise-chan)] 
  ;; takers
  (dotimes [_ 3] 
    (go (println (<! c)))) 

  ;; put, should get to all takers
  (go (>! c 1)))
Comment by Jozef Wagner [ 30/May/15 10:35 AM ]

ASYNC-124 fixes the issue mentioned by Alex

Comment by Leon Grapenthin [ 11/Jun/15 11:44 AM ]

Quote: "buf is never emptied: N consumers can all get the same, one and only value by reading from the channel"

This is not true with the new closing semantics introduced here, correct? If I deref a Clojure promise, I get the same value everytime. But what is the purpose in closing promise-chans after the promise has been delivered?

When is a good time to close a promise-chan? If I close after the put, which is what many core.async processes do, takers must have taken before the close which means it will often be a race condition unless explicit care is taken.

Is there a benefit or am I simply missing something here?

Comment by Herwig Hochleitner [ 08/Jul/15 2:23 PM ]

Here is my cljs implementation of a promise channel: https://github.com/webnf/webnf/blob/master/cljs/src/webnf/promise.cljs
I'm the sole author and you are free to use any of it.

Comment by Alex Miller [ 12/Aug/15 3: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.

Comment by Leon Grapenthin [ 23/Aug/15 6:46 AM ]

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?

Comment by Alex Miller [ 24/Aug/15 12: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).

Comment by Alex Miller [ 24/Aug/15 1: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.

Comment by Stuart Sierra [ 28/Aug/15 4: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.





[ASYNC-149] Cannot compile a recur in a case statement when in a go-loop with a <! Created: 29/Oct/15  Updated: 11/Nov/15  Resolved: 11/Nov/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Josh Comer Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

When compiling the following code causes a Caused by: java.lang.UnsupportedOperationException: Can only recur from tail position exception to be thrown (from the 1 line of the case):

(defn foo
  [x]
  (let [c (a/chan)]
    (a/go-loop [o 1]
      (when-let [r (a/<! c)]
        (case o
          1 (recur 2)
          2 (recur 3)
          3 false)))))

Interestingly this code does not create the exception:

(defn foo-2
  [x]
  (let [c (a/chan)]
    (a/go-loop [o 1]
      (when-let [r true]
        (case o
          1 (recur 2)
          2 (recur 3)
          3 false)))))

The error causing code compiles fine using 0.1.346.0-17112a-alpha. My first guess would be this has to do with the updating of tools.analyzer.jvm



 Comments   
Comment by Alex Miller [ 11/Nov/15 4:19 PM ]

Fixed by upgrade to latest tools.analyzer.jvm in https://github.com/clojure/core.async/commit/f01c280b68f0aa013e6aa08e08f25354f78ae343





[ASYNC-99] go block with <! inside protocol method invocation fails to compile (dispatch :protocol-invoke on '-item-to-ssa') Created: 23/Oct/14  Updated: 11/Nov/15  Resolved: 11/Nov/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Valentin Waeselynck Assignee: Unassigned
Resolution: Not Reproducible Votes: 4
Labels: go-macro, protocols
Environment:

[org.clojure/core.async "0.1.346.0-17112a-alpha"]
happened on both [org.clojure/clojure "1.7.0-alpha1"] and [org.clojure/clojure "1.6.0"]

java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)



 Description   

I was programming a function involving a core.async go block, when I stumbled on a strange compilation error :

CompilerException java.lang.IllegalArgumentException: No method in multimethod '-item-to-ssa' for dispatch value: :protocol-invoke, compiling:(NO_SOURCE_PATH:2:3)

I experimented a little to try and strip down the problem, and found it was very generic. Say I have any protocol MyProtocol :

(defprotocol MyProtocol
  (do-something [this param] "some method"))

The following code will not compile, failing with the exception I showed you above :

(defn uncompilable! [me ch] 
  (go 
    (do-something me (<! ch)) ;; apparently, it hurts to use <! in a protocol method invocation 
    ))

However, the following 2 will compile without any problem :

(defn compilable! [me ch] 
  (let [call-it #(do-something me %)] ; wrapping the protocol call in a function
    (go 
     (call-it (<! ch))
     )))

(defn compilable-2! [me ch] 
  (go 
    (let [my-value (<! ch)] ; taking out the <! call
      (do-something me my-value))
    ))

It seems to me the '<! inside protocol method invocation form' is a situation which the go macro fails to handle.



 Comments   
Comment by Alex Miller [ 11/Nov/15 5:13 PM ]

NR in latest core.async 0.2.374.





[ASYNC-164] Limited partition-all in pipeline Created: 19/Mar/16  Updated: 24/Mar/16  Resolved: 24/Mar/16

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Corin Lawson Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

a6dc01d2ebb692a39e923988b0853ff2bd1a431b



 Description   

Using partition-all as the transducer in a pipeline has unexpected results.

(let [to (chan)]
  (pipeline 1 to (partition-all 2) (to-chan (range)))
  (repeatedly 4 #(<!! to)))

Expected Output: ([0 1] [2 3] [4 5] [6 7])
Actual Output: ([0] [1] [2] [3])

It seems to me that the res channel should be created inside the dotimes form and closed when there are no more jobs. (This breaks the contract of the async function af). I have created a simplified version of pipeline (below) which exhibits the desired behaviour. (Note this is a modified version of the function that I submitted to ASYNC-150, i.e. it breaks the ordering of the output.) I attempted to modify the current definition of pipeline* but the p channels are confusing me (I don't understand why they are necessary) and failed in my effort to write a working patch.

(defn pipeline
  ([n to xf from] (pipeline n to xf from true))
  ([n to xf from close?] (pipeline n to xf from close? nil))
  ([n to xf from close? ex-handler]
   (assert (pos? n))
   (let [ex-handler (or ex-handler (fn [ex]
                                     (-> (Thread/currentThread)
                                         .getUncaughtExceptionHandler
                                         (.uncaughtException (Thread/currentThread) ex))
                                     nil))]
     (go
       (<! (async/merge
             (repeatedly n
                         #(let [res (chan 1 xf ex-handler)]
                            (go-loop []
                                     (if-let [v (<! from)]
                                       (do
                                         (>!! res v)
                                         (recur))
                                       (close! res)))
                            (go-loop []
                                     (let [v (<! res)]
                                       (when (and (not (nil? v)) (>! to v))
                                         (recur))))))))
       (when close? (close! to))))))


 Comments   
Comment by Kevin Downey [ 20/Mar/16 1:06 PM ]

this is not possible.

pipeline effectively runs a transducer in parallel, partition-all is based on sequential ordering. your rewritten pipeline will also fail to result in the partition you want.

if you look at the docstrings of transducer returning functions in core, some of them say "returns a transducer" some say "returns a stateful transducer", most stateful transducers will behave differently when run in parallel, because each concurrent instance will have its own state. partition-all is a stateful transducer.

Comment by Corin Lawson [ 20/Mar/16 4:02 PM ]

It is quite foolhardy to say my rewritten pipeline will fail to result in the partition I want, did you try it? I am very much aware that partition-all is a stateful tranducer; this fact is the crux of the problem, and the reason I wish to moved the res channel to the dotimes form, so that each of the n channels will maintain its own state. As I previously mentioned, order is unimportant to me but state is, the test that I actually need to pass is the following, in which my function succeeds and it also meets my other requirements. I share it here with you to show you the particular aspect of the behaviour that I expected from core.async/pipeline, nothing more.

(let [to (chan)]
  (pipeline 3 to (partition-all 2) (to-chan (range)))
  (repeatedly 4 #(-> to <!! count (= 2))))

Expected Output: (true true true true)

Comment by Kevin Downey [ 20/Mar/16 10:58 PM ]

perhaps I misunderstood, but in your example you said your expected output is

([0 1] [2 3] [4 5] [6 7])

which I read as an ordered processing of the input

Comment by Corin Lawson [ 20/Mar/16 11:02 PM ]

Perhaps, but the point I'm trying to make is about the size of the vectors in the output.

Comment by Kevin Downey [ 20/Mar/16 11:14 PM ]

the p channels are there to preserve the order of the output.

they are created and paired with jobs in the same order as jobs come in from the from channel, and put into the results channel in the same order, and then the final go loop copies from each channel in turn, preserving the order of results regardless of what order they generated in by the workers.

using the same channel(and transducer state) for the life time of the worker makes that ordering impossible. pipeline walks a line allowing a certain of random ordering of processing internally, but the order of the output is the order of the input.

there may be interest in something like this (I know I often don't really care about order) but it would be a large departure from the existing behavior of pipeline.

Comment by Corin Lawson [ 20/Mar/16 11:27 PM ]

Okay, that makes sense to me now, thank you. I agree, unordered output is a departure from the existing behaviour. I also accept that it is unreasonable to enforce an order over the output, any such ordering would be at the loss of parallelism.

(Please close, am I able to close this ticket myself?)

Comment by Kevin Downey [ 21/Mar/16 12:08 AM ]

I honestly don't know. I am a random guy on the internet, so you may want to leave it open and see if someone more closely tied to the project has thoughts

Comment by Corin Lawson [ 21/Mar/16 12:13 AM ]

Ha! Thank you fellow random guy on the internet!

Comment by Alex Miller [ 24/Mar/16 10:55 AM ]

Note that the pipeline docstring says "Because it is parallel, the transducer will be applied independently to each element, not across elements, and may produce zero or more outputs per input." which explains the results.

I would not expect a transducer with a stateful reducing function to work with the parallelism in partition-all (other than with the caveat specified above).





[ASYNC-160] `(vector :blah)` and `[:blah]` crashing with `inst_XXXX.call not a function` within core.async go routine Created: 20/Feb/16  Updated: 24/Mar/16  Resolved: 24/Mar/16

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Jonathan Leonard Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: None
Environment:

Node.js v4.1.1
Mac OS X 10.11.2
JVM 1.8.0_45



 Description   

Summary says it all.

[Worked around it by using a list rather than a vector (which compiled fine)].

I don't have time to create a minimal repro at the moment but if no one can repro this and it's necessary, I can devote time to that later.



 Comments   
Comment by Nicola Mometto [ 21/Feb/16 3:22 PM ]

This ticket doesn't have enough info to be useful:

user=> (go (vector :foo))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x3e59dd7e "clojure.core.async.impl.channels.ManyToManyChannel@3e59dd7e"]
user=> (go [:foo])
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x70b36700 "clojure.core.async.impl.channels.ManyToManyChannel@70b36700"]
Comment by Jonathan Leonard [ 21/Feb/16 3:33 PM ]

The actual code was more like:

(defn func []
  (go
    (let [...]
      (swap! an-atom update-in [:foo] ...))))

I would imagine that the let bindings themselves aren't the culprit but if you need yet more detail I will try to obfuscate them enough to provide them here.

Comment by Jonathan Leonard [ 21/Feb/16 3:35 PM ]

Also, this was from ClojureScript; not Clojure.

Comment by Nicola Mometto [ 21/Feb/16 3:50 PM ]

(swap! x [:foo] ..)
will invoke
(apply [:foo] @x ..)
which is probably not what you want and the cause of the exception you're seeing. Not a core.async bug

Comment by Jonathan Leonard [ 21/Feb/16 4:46 PM ]

Sorry, it was:

(swap! an-atom update-in [:foo] ...
Comment by Jonathan Leonard [ 21/Feb/16 4:48 PM ]

Also, note that changing [:foo] to (list :foo) or '(:foo) side stepped the erroneous compiler output and allowed to code to succeed without any additional changes anywhere to the code.

Comment by Nicola Mometto [ 21/Feb/16 5:20 PM ]

I'm sorry but this is still not enough information.
You're going to have to post an actual failing case if you want somebody to be able to help you

Comment by Jonathan Leonard [ 21/Feb/16 5:24 PM ]

This isn't a matter of helping me: I already have a workaround (namely use `(list ...)` instead of `(vector ...)`).

I reported the bug for everyone's benefit.

Comment by Nicola Mometto [ 21/Feb/16 5:51 PM ]

Let me rephrase

Opening a ticket with only assumptions about the cause of an issue you're seeing and no details about the actual code that's causing it, is not helpful to anybody, all we can do is play guesswork.

If you want a ticket to be helpful (either to you, to the users of the library or to its maintainers in fixing the reported issue), you're at least going to have to post enough information for maintainers/contributors to reproduce the supposed bug.

In this particular case, even without a reproducible case I can speculate that it's much more likely that the problem lies in your own code than in core.async: nothing in the `go` macro would make a call to `list` compile any different than a call to `vector`

Comment by Jonathan Leonard [ 21/Feb/16 9:13 PM ]

It sounds like you are making at least as many and as great in magnitude of assumptions as me (in fact more since I know the code in question and its resultant compiler output).

I will distill the code and post it so that all doubts may be removed.

Comment by Jonathan Leonard [ 21/Feb/16 10:38 PM ]

Here it is in all its glory:

(def a (atom {:a {:b '() :c '()}}))
(defn- repro-async-160 []
  (go
    (let [_ (<! (to-chan [1 2 3 4]))
          new (for [order (range 100)] nil)]
      (swap! a update-in [:a] assoc :b '() :c '()))))

Note that changing `new` to `z` avoids the issue. I suspect that identifier shadowing in let binding is not playing nicely with all the other macros in play (i.e., for & go).

Is `new` some kind of [undocumented] reserved word?

Comment by Jonathan Leonard [ 21/Feb/16 10:42 PM ]

Actually it may be colliding with the JavaScript notion of 'new' (in which case this is a ClojureScript bug and not a core.async-- but they sent me here first actually).

Comment by Nicola Mometto [ 22/Feb/16 3:24 AM ]

This sounds like a dupe of ASYNC-63

Comment by Alex Miller [ 24/Mar/16 10:58 AM ]

Dupe of ASYNC-63

Comment by Jonathan Leonard [ 24/Mar/16 12:10 PM ]

I'm not convinced that this is a duplicate. The repro steps and behavior are slightly different. It may certainly be merely a different manifestation of the same underlying or related issue and any potential fix may resolve both issues but I don't think (as an outside observer) that that is necessarily so.





[ASYNC-162] Published API docs seem way out of date Created: 27/Feb/16  Updated: 31/Mar/16  Resolved: 26/Mar/16

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Major
Reporter: Avi Flax Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: documentation


 Description   

The home page says that the current release is 0.2.374. When I follow the link API Docs that page says:

API for clojure.core.async - Facilities for async programming and communication 0.1.0 (in development)

Which doesn't give me much confidence that the docs are accurate for the current version of the library.



 Comments   
Comment by Alex Miller [ 24/Mar/16 10:47 AM ]

I think that 0.1.0 must be hard-coded into the doc generation somewhere - I will track that down. The docs are current though for released version.

Comment by Alex Miller [ 26/Mar/16 8:12 AM ]

Updated docs to report the major/minor version based on the code.

The docs themselves were and are up to date with the latest release.

Comment by Avi Flax [ 31/Mar/16 10:08 AM ]

That's excellent! Thanks!





[ASYNC-171] bounded-count appears in both clojure.core and clojure.core.async Created: 05/Jul/16  Updated: 06/Sep/16  Resolved: 05/Jul/16

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Chelimsky Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None
Environment:

clojure-1.9.0-alpha8 and core.async-0.2.385



 Description   

WARNING: bounded-count already refers to: #'clojure.core/bounded-count in namespace: clojure.core.async, being replaced by: #'clojure.core.async/bounded-count



 Comments   
Comment by Alex Miller [ 05/Jul/16 8:33 AM ]

Fixed in master for next release

Comment by Mike Fikes [ 06/Sep/16 10:18 PM ]

See ASYNC-175 for an associated regression.





[ASYNC-110] 0.1.346, using >! crashes with no method 'setTimeout', when targeting node Created: 23/Dec/14  Updated: 21/Sep/16  Resolved: 12/Feb/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: William Assignee: Unassigned
Resolution: Completed Votes: 3
Labels: bug, nodejs
Environment:

[[org.clojure/clojure "1.6.0"]
[org.clojure/core.async "0.1.346.0-17112a-alpha"]
[org.clojure/clojurescript "0.0-2511"]]


Attachments: Text File async-110-exportSymbol.patch     Text File br.log    

 Description   

When targeting node, running a simple >! crashes immediately:

(let [a (chan)]
  (go (>! a :hi))
  (go (println (<! a))))

Crashes with:

goog.global.setTimeout(cb, 0);
   ^
TypeError: Object #<Object> has no method 'setTimeout'

This works fine with 0.1.338.0-5c5012-alpha.



 Comments   
Comment by Joel Wilsson [ 01/Feb/15 3:34 PM ]

The problem is really in the ClojureScript compiler. It does not export those NodeJS global functions. I have a fix that works for me and seems sound, so I submitted a pull request: https://github.com/clojure/clojurescript/pull/45

Comment by David Nolen [ 01/Feb/15 3:47 PM ]

I'm not convinced yet that there are any issues with the ClojureScript compiler nor that your PR represents the solution we should pursue.

Before we even begin assessing any solution first someone needs to identify precisely why the goog.async.nextTick detection doesn't pick up the Node.js globals. The first thing that Google Closure library does is map the global environment to goog.global. I'm curious as to why this isn't working in this case.

Comment by Joel Wilsson [ 01/Feb/15 3:47 PM ]

Patch from the pull request attached.

Comment by Joel Wilsson [ 03/Feb/15 3:49 PM ]

Yes, the first thing the Google Closure library is set up a reference to the global environment with goog.global = this;

However, this is not the global environment in Node.js. From http://nodejs.org/api/vm.html#vm_sandboxes:

the this expression within the global scope of the context evaluates to the empty object ({}) instead of to your sandbox.

If you start a Node.js REPL and enter console.log(this) you will see that this is in fact the global environment. However, if you put that statement in a file and run it with nodejs <filename>, the output will be "{}".

Some possible solutions:

  1. Use goog.exportSymbol to get these functions into goog.global, as in the patch I attached. A drawback of this approach is that it is using goog to fix goog, so it must be done after goog has been loaded.
  2. Explicitly set properties on this before doing anything else. This is the simplest solution. Preamble:
    this.setTimeout = setTimeout;
    this.clearTimeout = clearTimeout;
    this.setInterval = setInterval;
    this.clearInterval = clearInterval;
  3. Use vm.Script.runInThisContext, as bootstrap_node.js does to load base.js with this referencing the global environment found in the variable global.
    A bit tricky in this case, since the file we're executing needs to read itself, but it can be done with this preamble:
    if (!this.__nodeFilename) {
        var vm = require('vm');
        var fs = require('fs');
        global.__nodeFilename = __filename;
        vm.runInThisContext.call(global, fs.readFileSync(__nodeFilename), __nodeFilename);
        process.exit(0);
    }

    For this to work the hashbang must be removed, since #!/usr/bin/env node is not valid JavaScript. Since node is a symlink to ax25-node on Ubuntu, and the Node.js binary is called "nodejs", this might be a good idea either way.
    While this solution is the closest to bootstrap_node.js, it is complex and may be a bit too clever.

  4. Convince the Closure library maintainers to check if base.js is being loaded in Node.js and do goog.global = global; if that is the case.

With 3 and 4, goog.global will contain a lot of Node.js stuff. That may or may not be a good thing. Considering the effort in bootstrap node to hide module and exports, I'm guessing it's a bad thing.

From what I can tell, programs using the Closure library, and which have been compiled by the Closure compiler into a single file, have never worked properly if they have been using anything that needs setTimeout and friends.

Comment by David Nolen [ 03/Feb/15 3:53 PM ]

Joel, many thanks for all the extra information. Will sort through this and think about it.

Comment by David Nolen [ 10/Feb/15 12:00 PM ]

Issue is confirmed on this end. Will look into.

Comment by David Nolen [ 10/Feb/15 12:41 PM ]

So I looked into this a bit, this does not actually appear to be a real issue, at least not yet. The Node.js environment must be bootstrapped for ClojureScript to work. However this process could be simpler and we will address the usability bits in ClojureScript. When it's resolved there and we can confirm via automated testing in core.async we will close this ticket.

Comment by Stuart Mitchell [ 11/Feb/15 8:16 PM ]

Not quite sure what you mean by 'not a real problem' as I have a clojurescript project that targets atom-shell that worked with 0.1.338.0-5c5012-alpha but now doesn't.

Do you mean that its actually a clojurescript issue, if so is there a bug report/ work around?

Comment by Joel Wilsson [ 12/Feb/15 7:58 AM ]

Stuart, could you please try the four lines from option 2 in my previous comment as a preamble and let me know if that solves the problem for you? Ie. put them in a file preamble.js on your project's classpath (I use resources/) and add :preamble "preamble.js" to your :compiler settings. Assuming that you are using lein-cljsbuild, that is.

This is a real issue for me as well, because it stops me from using core.async on AWS Lambda.

Comment by David Nolen [ 12/Feb/15 8:10 AM ]

Sorry Stuart I'm not saying it's not real a issue but rather that I'm trying to determine the scope and precise nature of the issue. I noticed that the problem does not manifest when I use :optimizations :none. Are you and Joel using :simple, :advanced? Thanks.

Comment by Joel Wilsson [ 12/Feb/15 8:23 AM ]

I use :simple to get a single JavaScript file, which I can then use with AWS Lambda with this in main.js:

var r = require("./clojurescript-output.js");
exports.handler = r.hello_lambda.core.handler;

where clojurescript-output.js is generated from a file like

(ns hello_lambda.core)
(enable-console-print!)
(defn ^:export handler [event context]
  (println "Hello AWS Lambda")
  (.done context))

:advanced doesn't work for me: it just creates a JavaScript file with a single (function () {...})(), which makes it useless for creating a module (the symbols are not exported properly), but that's another issue.

Comment by David Nolen [ 12/Feb/15 9:11 AM ]

this was in fact an upstream ClojureScript issue, fixed as of this commit https://github.com/clojure/clojurescript/commit/e8ae2c8a9c3f2429555e136cc17c1669be5e993a

Comment by Dusan Maliarik [ 12/Jul/16 3:41 PM ]

Not entirely fixed. If you use cljs.core.async/pub in the namespace,

eg. http://stackoverflow.com/questions/24698536/how-to-memoize-a-function-that-uses-core-async-and-non-blocking-channel-read/38069830#38069830
(then using it in some namespace)

(ns foo
  (:require ....))

(def foo
  (memoize-async
    (fn [...] ...)))

then goog.global.setTimeout is called before the cljs.nodejscli is evaled. Therefore causing

/home/skrat/Workspace/xxx/yyy.drie/bin/convert:37684
    goog.global.setTimeout(a, 0);
                ^

TypeError: goog.global.setTimeout is not a function
    at Function.setImmediate_ (/home/skrat/Workspace/xxx/yyy.drie/bin/convert:37684:17)
    at Object.goog.async.nextTick (/home/skrat/Workspace/xxx/yyy.drie/bin/convert:37630:270)
    at Object.cljs.core.async.impl.dispatch.queue_dispatcher (/home/skrat/Workspace/xxx/yyy.drie/bin/convert:37718:21)
    at Object.cljs.core.async.impl.dispatch.run (/home/skrat/Workspace/xxx/yyy.drie/bin/convert:37722:40)
    at Function.cljs.core.async.pub.cljs$core$IFn$_invoke$arity$3 (/home/skrat/Workspace/xxx/yyy.drie/bin/convert:40775:33)
    at Function.cljs.core.async.pub.cljs$core$IFn$_invoke$arity$2 (/home/skrat/Workspace/xxx/yyy.drie/bin/convert:40703:30)
    at Object.yyy.drie.io.async.memoize_async (/home/skrat/Workspace/xxx/yyy.drie/bin/convert:42231:89)
    at Object.<anonymous> (/home/skrat/Workspace/xxx/yyy.drie/bin/convert:59163:41)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)

I tried to require cljs.nodejscli in the ns that contains my main fn, but it results in

SEVERE: cljs.nodejscli:1: ERROR - namespace "cljs.nodejscli" cannot be provided twice
goog.provide('cljs.nodejscli');
^

Jul 12, 2016 2:34:34 PM com.google.javascript.jscomp.LoggerErrorManager printSummary
WARNING: 1 error(s), 0 warning(s)
ERROR: JSC_DUPLICATE_NAMESPACE_ERROR. namespace "cljs.nodejscli" cannot be provided twice at cljs.nodejscli line 1 : 0
Comment by Dusan Maliarik [ 12/Jul/16 3:44 PM ]

I believe the solution is to include cljs.nodejscli as soon as possible, instead of appending it at the end. This also means it has to be split into two pieces, one dealing with goog.global (included asap), and another one dealing with main-cli-fn (included at the end as is the case now).

Comment by Nick Alexander [ 21/Sep/16 5:34 PM ]

I am seeing this, with `optimizations :advanced` and `:simple`, with the following project https://github.com/ncalexan/datomish-user-agent-service/commit/af99ad3a16eece881a48fedd0b0f62517bb5cb25. It's not going to be 100% easy to duplicate, since an underlying library isn't published on Maven Central yet, but I can reproduce this consistently.

Any help?

Comment by Nick Alexander [ 21/Sep/16 6:10 PM ]

For the next poor sod who runs into this, it is triggered by having a `go` at top-level.

Hat tip to user "Roc King" in the post http://clojure.2344290.n4.nabble.com/Will-advanced-optimizations-be-officially-supported-on-nodejs-tp7762p7855.html, who writes [sic]:

After got more familiar with clojurescript, I realized that ASYNC-110 fully described(and gave several working solutions!)[3] this issue.
But if "goog.global" was used before "goog.global = global"(the solution used in clojurescript[4]), the same problem will occur.
This is the exactly situation I have encountered several days ago: I wrote '(go (<! (timeout 1212)) ...)' in top level.

This was not clear to me until I read Roc's note. After I remove my top-level `go`, everything is happy.





[ASYNC-181] Expose unblocking-buffer? on channels Created: 11/Oct/16  Updated: 15/Oct/16  Resolved: 13/Oct/16

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Nick Alexander Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

For a generic listener implementation, where consumers are not controlled, I want to ensure that put! doesn't block. `unblocking-buffer?` does exactly this... but it's not exposed on channels. The work-around is to access the underlying buffer, which is an implementation detail. Can we expose this (unblocking?) on channels directly?



 Comments   
Comment by Richard Newman [ 11/Oct/16 3:23 PM ]

Specifically:

(defn unblocking-channel? [chan]
  (a/unblocking-buffer? (#?(:cljs .-buf :clj .buf) chan))
Comment by Alex Miller [ 13/Oct/16 9:34 AM ]

You can use offer! for this...

Comment by Nick Alexander [ 15/Oct/16 3:28 PM ]

I have a mult for which I want to ensure the taps do not block the distribution. I do not see how to use offer! to ensure that taps that can accept, do accept; and that slow taps do not block the mult. Can you elaborate?





[ASYNC-100] core.async with multiple catch blocks causing weird loop behaviour Created: 27/Oct/14  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Tom Coupland Assignee: Unassigned
Resolution: Duplicate Votes: 7
Labels: try-catch

Attachments: Text File ASYNC-100_2.patch    
Patch: Code and Test
Approval: Triaged

 Description   

I've been seeing this weird looping behavior with some go loops over the last few days. An exception is being thrown from a function within the loop and rather than logging and looping back around to a waiting take, the loop seems to just hop back to the line before the function call.

I've managed to boil it down to the following:

(def s (chan))
(def single
  (go-loop []
    (try
      (prn "Awaiting single")
      (<! s)
      (prn "Single")
      (throw (new Throwable))
      (catch Throwable t
        (prn t)))
    (recur)))

(def d (chan))
(def double
  (go-loop []
    (try
      (prn "Awaiting double")
      (<! d)
      (prn "Double")
      (throw (new Throwable))
      (catch Exception re
        (prn re))
      (catch Throwable t
        (prn t)))
    (recur)))

Now if you (>!! s :a), you'll see the throwable printed out and the loop go back to waiting on the s channel. However, (>!! d :a) and you'll get to enjoy an infinite stream of 'Double'. In actual fact you can remove the -loop from double and get the same result.

Not sure what's going on here at all. In the macro expanded version of double '(prn t)' doesn't appear at all (it does in single's expansion), so it looks like it's not surviving the move into the state machine and instead is routing back to (prn "Double") or the take isn't really completing somehow, leaving the :a on the chan.



 Comments   
Comment by Paavo Parkkinen [ 03/Dec/14 5:30 PM ]

From my experiments, it seems what's causing the issue isn't the two catch clauses, but the fact that you are catching an Exception first, and then the Throwable. When I switched the two catch clauses (Throwable first) the issue went away.

You don't even need the two catch clauses to trigger it, a single catch clause of an Exception will do.

;; Works
(require '[clojure.core.async :as async])
(def c (async/chan))
(def st
  (async/go-loop []
    (try
      (prn "Awaiting")
      (async/<! c)
      (prn "Received")
      (throw (new Throwable))
      (catch Throwable t
             (prn t)))
    (recur)))
(async/>!! c :a)
;; Doesn't work
(require '[clojure.core.async :as async])
(def c (async/chan))
(def se
  (async/go-loop []
    (try
      (prn "Awaiting")
      (async/<! c)
      (prn "Received")
      (throw (new Throwable))
      (catch Exception t
             (prn t)))
    (recur)))
(async/>!! c :a)
Comment by Paavo Parkkinen [ 04/Dec/14 12:18 AM ]

Attaching a patch that fixes the original issue, but not the one in my comment above with an uncaught exception. All test cases pass.

Instead of just picking the first catch block, and creating a state machine block and exception frame for that one, I create blocks and frames for all of them.

I tried creating a test case too, but was unable to create one that would reproduce the error. I'll spend some more time trying to write a test case, but I wanted to submit the code patch without the test coverage first.

Comment by Paavo Parkkinen [ 04/Dec/14 7:45 PM ]

Attached patch with test case included.

Comment by Stuart Sierra [ 18/Jun/15 2:52 PM ]

Possible workaround until this is fixed: Just have one catch clause, catching all Throwable. Then examine the type of the throwable object inside the catch block to decide what to do.

Comment by Ken Allen [ 29/Oct/15 1:34 PM ]

This is even more troublesome when the exception is thrown from code that's not part of what the user wrote in the go block. You don't even need a loop for it to loop forever:

(require '[clojure.core.async :as async])
(def c (async/chan))
(doseq [_ (range 1024)] (async/put! c :test))
(async/go (try (println "BEFORE") (async/>! c :test) (catch Exception ex (println "ERR"))))

This was confusing as hell when we ran into it but catching Throwable instead does indeed work around the problem so that's what we've been doing. Was hoping the latest release of core.async would fix this.

Comment by Thomas Getgood [ 26/Jan/16 10:46 AM ]

As it is, you need to catch Throwable or nothing. Unhandled Throwables will cause this as well.

(require '[clojure.core.async :refer [go <! put! chan]])
(def ch (chan))
(go (try (print (<! ch)) (assert false) (catch Exception e nil)))
(put! ch 1)

Will print an infinite stream of 1s.

It was a lot of fun figuring out why functions failing :pre conditions caused infinite loops.

Comment by Kevin Downey [ 17/May/16 8:08 PM ]

the patch here no longer applies. http://dev.clojure.org/jira/browse/ASYNC-169 is a dupe of this, but it has a patch that applies

Comment by Alex Miller [ 13/Feb/17 2:29 PM ]

Marking as duplicate of ASYNC-169 which seems to address this issue as well.





[ASYNC-180] (go (try ... (finally ...))) block with parking operations in finally body loses try body return value Created: 07/Oct/16  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nick Alexander Assignee: Unassigned
Resolution: Duplicate Votes: 1
Labels: None
Environment:

[org.clojure/clojure "1.8.0"]
[org.clojure/core.async "0.2.385"]



 Description   

As it says. A parking operation in the finally body loses the try body return value. See the following test case:

(ns finally-testcase
  (:require
   [clojure.core.async :as a :refer :all ;[go go-loop <! >! go timeout]
    ]))

(def t1
  (go
    (try
      1
      (finally
        2))))

(def t2
  (go
    (try
      (<! (timeout 100))
      1
      (finally
        2))))

(def t3
  (go
    (try
      1
      (finally
        (<! (timeout 100))
        2))))

(println (<!! t1)) ;; => 1, as expected
(println (<!! t2)) ;; => 1, as expected
(println (<!! t3)) ;; => nil -- not expected!


 Comments   
Comment by Nick Alexander [ 07/Oct/16 3:39 PM ]
Unable to find source-code formatter for language: clojure. Available languages are: javascript, sql, xhtml, actionscript, none, html, xml, java
(ns finally-testcase
  (:require
   [clojure.core.async :as a :refer :all ;[go go-loop <! >! go timeout]
    ]))

(def t1
  (go
    (try
      1
      (finally
        2))))

(def t2
  (go
    (try
      (<! (timeout 100))
      1
      (finally
        2))))

(def t3
  (go
    (try
      1
      (finally
        (<! (timeout 100))
        2))))

(println (<!! t1)) ;; => 1, as expected
(println (<!! t2)) ;; => 1, as expected
(println (<!! t3)) ;; => nil -- not expected!
Comment by Nick Alexander [ 07/Oct/16 3:39 PM ]

Somebody with edit rights can format the original comment correctly.

Comment by Kevin Downey [ 10/Oct/16 7:27 PM ]

the patch on http://dev.clojure.org/jira/browse/ASYNC-169 fixes this

Comment by Alex Miller [ 13/Feb/17 2:37 PM ]

Marking as duplicate of ASYNC-169.





[ASYNC-179] parking take in finally clause in go block causes try expression to yield the finally clause result Created: 20/Sep/16  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Valentin Waeselynck Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: try-catch
Environment:

core.async 0.2.391, Clojure 1.8.0,

java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)

OS X Yosemite 10.10.5, MacBook Air (11-inch, Early 2015)



 Description   

Inside a go block, in a try-catch-finally clause,
if the finally-clause consists of a parking take (<!),
the try-catch-finally will yield the result of the finally, instead of the try body.

e.g

(a/<!! (go
         (try :a
           (finally :b))))
=> :a ;; expected

;; whereas:
(a/<!! (go
         (try :a
           (finally (<! (go :b))))))
=> :b ;; wrong

Repro project on Github.



 Comments   
Comment by Valentin Waeselynck [ 20/Sep/16 10:48 AM ]

Duplicate of http://dev.clojure.org/jira/browse/ASYNC-122.

Comment by Alex Miller [ 13/Feb/17 2:38 PM ]

Marking as duplicate of ASYNC-169.





[ASYNC-122] Parking in finally block replaces result Created: 06/May/15  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Vesa Karvonen Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: try-catch
Environment:

[org.clojure/clojurescript "0.0-3211"]
[org.clojure/clojure "1.6.0"]
[org.clojure/core.async "0.1.346.0-17112a-alpha"]


Approval: Triaged

 Description   

Because

(try 1 (finally 2))

evaluates to 1, I would expect

(go (println (try 1 (finally (<! (go 2))))))

to print 1, but it prints 2 in both CLJ and CLJS. This can be worked around by replacing try-finally with try-catch.



 Comments   
Comment by Nicola Mometto [ 17/Dec/15 10:06 AM ]

This appears to be a bug caused by nesting `go` blocks

Comment by Kevin Downey [ 17/May/16 7:54 PM ]

the patch on http://dev.clojure.org/jira/browse/ASYNC-169 appears to fix this

Comment by Alex Miller [ 13/Feb/17 2:39 PM ]

Marking as duplicate of ASYNC-169.





[ASYNC-178] First pending put into a channel always succeeds even if the buffer is full Created: 16/Sep/16  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Alexander Yakushev Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

[org.clojure/clojure "1.9.0-alpha10"]
[org.clojure/core.async "0.2.385"]



 Description   

Say we have a channel with a fixed buffer and a generating transducer (e.g. cat), and a pending put is scheduled into that channel. Then, the take from the channel will invoke the first pending put, even if the buffer is still full after the take.

Example scenario:

(def c (a/chan 10 cat))

(go-loop [i 0]
  (let [batch (range i (+ i 3))]
    (when (>! c batch)
      (println "Put succeeded:" batch)
      (recur (+ i 3)))))

;; Put succeeded: (0 1 2)
;; Put succeeded: (3 4 5)
;; Put succeeded: (6 7 8)
;; Put succeeded: (9 10 11)

;; // Predictable so far. Buffer filled up to 12 items and the next put blocked.

(<!! c) ; => 0
;; Put succeeded: (12 13 14)

(<!! c) ; => 1
;; Put succeeded: (15 16 17)

(<!! c) ; => 2
;; Put succeeded: (18 19 20)

;; // What? The buffer keeps growing after each single take!

Because of this, I cannot use backpressure with generative transducers, since the size of the fixed buffer, in this case, may grow infinitely.

I believe, the issue is here: https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async/impl/channels.clj#L182. If the buffer was checked for fullness before the first pending put is executed, the issue would be solved. If this is confirmed to be a bug (not the intended behavior) I will submit a patch.



 Comments   
Comment by Alex Miller [ 13/Feb/17 2:41 PM ]

This is the expected behavior. Expanding transducers must always be able to put and are allowed to do so even when the buffer is full. If this is an issue for back-pressure for you, you should pull the transducer out of the channel and do the expansion in a go process.





[ASYNC-78] deadlock in multi catch Created: 05/Jul/14  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Lars Bohl Assignee: Unassigned
Resolution: Duplicate Votes: 1
Labels: try-catch
Environment:

ubuntu 14.04
Leiningen 2.4.2 on Java 1.7.0_60 Java HotSpot(TM) 64-Bit Server VM
[org.clojure/clojure "1.6.0"]
[org.clojure/core.async "0.1.303.0-886421-alpha"]



 Description   

The following apparently never returns:

(defn thread-death []
  (<!! (go
        (<!
         (let [ch (chan 1)]
           (>! ch 0)
           (>! ch (try (<! ch)
                       (assert false)
                       (catch Exception _ 5)
                       (catch AssertionError _ 4)))
           ch)))))

After removing the (catch Exception _ 5) catch block it returns 4 as expected.



 Comments   
Comment by Kevin Downey [ 17/May/16 7:52 PM ]

this is the same faulty exception handling also reported in http://dev.clojure.org/jira/browse/ASYNC-169

Comment by Alex Miller [ 13/Feb/17 2:48 PM ]

Marking as dupe of ASYNC-169





[ASYNC-168] Bad interaction between go, try and fn body Created: 11/May/16  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Moritz Heidkamp Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: try-catch
Environment:

[org.clojure/clojure "1.8.0"]
[org.clojure/core.async "0.2.374"]



 Description   

The following code incorrectly uses <! in a fn body within go. This should usually lead to a corresponding AssertionError but if there is a catch clause which catches Exception, this error is silently swallowed and the execution goes into an infinite loop.

(require '[clojure.core.async :as async])

(async/go
  (try ((fn []
          (println "Hello")
          (async/<! (async/timeout 1000))))
       (catch Exception e)))

Output:

Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
...

This only happens when there are (catch ...) clauses for any exception types which aren't in the inheritance hierarchy of AssertionError, e.g. it works fine with (catch Error ...) but also fails with (catch RuntimeException ...).



 Comments   
Comment by Kevin Downey [ 11/May/16 11:14 AM ]

It seems like using <! outside of a go block would be much better handled as a compilation error, instead of a runtime error. if the defns for the operators that are handled specially by go blocks were removed, then we would get compile time errors for incorrect usage. I am not sure what the motivation was for adding them, maybe for doc strings? Seems like a case were trying to make it easier to find docs made the library harder to use.

Comment by Moritz Heidkamp [ 11/May/16 4:23 PM ]

That would most likely fix this issue, indeed. The docstring situation is a bit unfortunate, though. This would also affect alts! and alt!, by the way.

However, it might be worth looking into some more beyond that: The buggy behavior isn't triggered when replacing (async/<! (async/timeout 1000)) with something like (assert false), for example, so something seems to be going wrong in the state machine transformation there when <! et. al. are present.

Comment by Kevin Downey [ 17/May/16 7:38 PM ]

actually, I am pretty sure this is due to general brokeness in the go macros exception handling, see http://dev.clojure.org/jira/browse/ASYNC-169 (there is a patch that could use testing if you are inclined)

Comment by Alex Miller [ 13/Feb/17 3:02 PM ]

With ASYNC-169 applied, I see:

Hello
Exception in thread "async-dispatch-1" java.lang.AssertionError: Assert failed: <! used not in (go ...) block

which is what I'd expect, so marking as dupe of ASYNC-169.





[ASYNC-154] (require :reload-all) causes NullPointerException Created: 29/Nov/15  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Aaron Cummings Assignee: Unassigned
Resolution: Completed Votes: 1
Labels: None
Environment:

Both Oracle and IBM JDK (1.7) affected.


Approval: Triaged

 Description   

I'm seeing a problem with (require :reload-all ...) with clojure.core.async, where running with :reload-all causes a NullPointerException as shown below.

Curiously, this does not happen with 'lein repl'; it seems the :reload-all is being somehow inhibited there.

So, starting the REPL like this:

java -cp asm-all-4.2.jar:clojure-1.7.0.jar:core.async-0.2.374.jar:core.cache-0.6.4.jar:core.memoize-0.5.8.jar:data.priority-map-0.0.7.jar:tools.analyzer-0.6.7.jar:tools.analyzer.jvm-0.6.9.jar:tools.reader-1.0.0-alpha1.jar clojure.main

Results below:

Clojure 1.7.0
user=> (require ['clojure.core.async])
nil
user=> (require :reload-all ['clojure.core.async])
CompilerException java.lang.NullPointerException, compiling:(clojure/core/async.clj:1138:8) 
user=> *e
#error {
 :cause nil
 :via
 [{:type clojure.lang.Compiler$CompilerException
   :message "java.lang.NullPointerException, compiling:(clojure/core/async.clj:1138:8)"
   :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6730]}
  {:type java.lang.NullPointerException
   :message nil
   :at [clojure.tools.analyzer.passes.jvm.warn_on_reflection$eval10493$fn__10494 invoke "warn_on_reflection.clj" 58]}]
 :trace
 [[clojure.tools.analyzer.passes.jvm.warn_on_reflection$eval10493$fn__10494 invoke "warn_on_reflection.clj" 58]
  [clojure.lang.MultiFn invoke "MultiFn.java" 229]
  [clojure.lang.Var invoke "Var.java" 379]
  [clojure.tools.analyzer.passes$compile_passes$fn__8431$fn__8436 invoke "passes.clj" 166]
  [clojure.tools.analyzer.passes$compile_passes$fn__8431$fn__8438 invoke "passes.clj" 168]
  [clojure.tools.analyzer.passes$compile_passes$fn__8431$fn__8438 invoke "passes.clj" 168]
  [clojure.tools.analyzer.passes$compile_passes$fn__8431$fn__8438 invoke "passes.clj" 168]
  [clojure.tools.analyzer.passes$compile_passes$fn__8431$fn__8438 invoke "passes.clj" 168]
  [clojure.core$partial$fn__4529 invoke "core.clj" 2500]
  [clojure.tools.analyzer.ast$walk$walk__8336 invoke "ast.clj" 99]
  [clojure.tools.analyzer.ast$walk$walk__8336$walk__8337 invoke "ast.clj" 96]
  [clojure.tools.analyzer.ast$_update_children$fn__8327 invoke "ast.clj" 51]
  [clojure.lang.PersistentVector reduce "PersistentVector.java" 333]
  [clojure.core$reduce invoke "core.clj" 6518]
  [clojure.tools.analyzer.ast$_update_children invoke "ast.clj" 49]
  [clojure.tools.analyzer.ast$update_children_reduced invoke "ast.clj" 64]
  [clojure.tools.analyzer.ast$walk$walk__8336 invoke "ast.clj" 99]
  [clojure.tools.analyzer.ast$walk$walk__8336$walk__8337 invoke "ast.clj" 96]
  [clojure.tools.analyzer.utils$mapv_SINGLEQUOTE_ invoke "utils.clj" 208]
  [clojure.tools.analyzer.ast$_update_children$fn__8327 invoke "ast.clj" 51]
  [clojure.lang.PersistentVector reduce "PersistentVector.java" 333]
  [clojure.core$reduce invoke "core.clj" 6518]
  [clojure.tools.analyzer.ast$_update_children invoke "ast.clj" 49]
  [clojure.tools.analyzer.ast$update_children_reduced invoke "ast.clj" 64]
  [clojure.tools.analyzer.ast$walk$walk__8336 invoke "ast.clj" 99]
  [clojure.tools.analyzer.ast$walk$walk__8336$walk__8337 invoke "ast.clj" 96]
  [clojure.tools.analyzer.ast$_update_children$fn__8327 invoke "ast.clj" 51]
  [clojure.lang.PersistentVector reduce "PersistentVector.java" 333]
  [clojure.core$reduce invoke "core.clj" 6518]
  [clojure.tools.analyzer.ast$_update_children invoke "ast.clj" 49]
  [clojure.tools.analyzer.ast$update_children_reduced invoke "ast.clj" 64]
  [clojure.tools.analyzer.ast$walk$walk__8336 invoke "ast.clj" 99]
  [clojure.tools.analyzer.ast$walk invoke "ast.clj" 95]
  [clojure.tools.analyzer.ast$walk invoke "ast.clj" 92]
  [clojure.tools.analyzer.ast$prewalk invoke "ast.clj" 108]
  [clojure.tools.analyzer.passes$compile_passes$analyze__8443 invoke "passes.clj" 170]
  [clojure.core$comp$fn__4495 invoke "core.clj" 2438]
  [clojure.core$comp$fn__4495 invoke "core.clj" 2438]
  [clojure.core$comp$fn__4495 invoke "core.clj" 2438]
  [clojure.core$comp$fn__4495 invoke "core.clj" 2438]
  [clojure.core$comp$fn__4495 invoke "core.clj" 2438]
  [clojure.core$comp$fn__4495 invoke "core.clj" 2438]
  [clojure.tools.analyzer.jvm$analyze$fn__11679 invoke "jvm.clj" 469]
  [clojure.lang.AFn applyToHelper "AFn.java" 152]
  [clojure.lang.AFn applyTo "AFn.java" 144]
  [clojure.core$apply invoke "core.clj" 630]
  [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1868]
  [clojure.lang.RestFn invoke "RestFn.java" 425]
  [clojure.tools.analyzer.jvm$analyze invoke "jvm.clj" 456]
  [clojure.core.async.impl.ioc_macros$state_machine invoke "ioc_macros.clj" 1109]
  [clojure.core.async$go doInvoke "async.clj" 413]
  [clojure.lang.RestFn invoke "RestFn.java" 442]
  [clojure.lang.Var invoke "Var.java" 388]
  [clojure.lang.AFn applyToHelper "AFn.java" 160]
  [clojure.lang.Var applyTo "Var.java" 700]
  [clojure.lang.Compiler macroexpand1 "Compiler.java" 6631]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 6709]
  [clojure.lang.Compiler analyze "Compiler.java" 6524]
  [clojure.lang.Compiler analyze "Compiler.java" 6485]
  [clojure.lang.Compiler$BodyExpr$Parser parse "Compiler.java" 5861]
  [clojure.lang.Compiler$LetExpr$Parser parse "Compiler.java" 6179]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 6723]
  [clojure.lang.Compiler analyze "Compiler.java" 6524]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 6711]
  [clojure.lang.Compiler analyze "Compiler.java" 6524]
  [clojure.lang.Compiler analyze "Compiler.java" 6485]
  [clojure.lang.Compiler$BodyExpr$Parser parse "Compiler.java" 5861]
  [clojure.lang.Compiler$FnMethod parse "Compiler.java" 5296]
  [clojure.lang.Compiler$FnExpr parse "Compiler.java" 3925]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 6721]
  [clojure.lang.Compiler analyze "Compiler.java" 6524]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 6711]
  [clojure.lang.Compiler analyze "Compiler.java" 6524]
  [clojure.lang.Compiler access$300 "Compiler.java" 38]
  [clojure.lang.Compiler$DefExpr$Parser parse "Compiler.java" 577]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 6723]
  [clojure.lang.Compiler analyze "Compiler.java" 6524]
  [clojure.lang.Compiler analyze "Compiler.java" 6485]
  [clojure.lang.Compiler eval "Compiler.java" 6786]
  [clojure.lang.Compiler load "Compiler.java" 7227]
  [clojure.lang.RT loadResourceScript "RT.java" 371]
  [clojure.lang.RT loadResourceScript "RT.java" 362]
  [clojure.lang.RT load "RT.java" 446]
  [clojure.lang.RT load "RT.java" 412]
  [clojure.core$load$fn__5448 invoke "core.clj" 5866]
  [clojure.core$load doInvoke "core.clj" 5865]
  [clojure.lang.RestFn invoke "RestFn.java" 408]
  [clojure.core$load_one invoke "core.clj" 5671]
  [clojure.core$load_all$fn__5389$fn__5392 invoke "core.clj" 5688]
  [clojure.core$load_all$fn__5389 invoke "core.clj" 5687]
  [clojure.lang.AFn call "AFn.java" 18]
  [clojure.lang.LockingTransaction run "LockingTransaction.java" 273]
  [clojure.lang.LockingTransaction runInTransaction "LockingTransaction.java" 229]
  [clojure.core$load_all invoke "core.clj" 5685]
  [clojure.core$load_lib$fn__5397 invoke "core.clj" 5711]
  [clojure.core$load_lib doInvoke "core.clj" 5710]
  [clojure.lang.RestFn applyTo "RestFn.java" 142]
  [clojure.core$apply invoke "core.clj" 632]
  [clojure.core$load_libs doInvoke "core.clj" 5749]
  [clojure.lang.RestFn applyTo "RestFn.java" 137]
  [clojure.core$apply invoke "core.clj" 632]
  [clojure.core$require doInvoke "core.clj" 5832]
  [clojure.lang.RestFn invoke "RestFn.java" 421]
  [user$eval7383 invoke "NO_SOURCE_FILE" 2]
  [clojure.lang.Compiler eval "Compiler.java" 6782]
  [clojure.lang.Compiler eval "Compiler.java" 6745]
  [clojure.core$eval invoke "core.clj" 3081]
  [clojure.main$repl$read_eval_print__7099$fn__7102 invoke "main.clj" 240]
  [clojure.main$repl$read_eval_print__7099 invoke "main.clj" 240]
  [clojure.main$repl$fn__7108 invoke "main.clj" 258]
  [clojure.main$repl doInvoke "main.clj" 258]
  [clojure.lang.RestFn invoke "RestFn.java" 421]
  [clojure.main$repl_opt invoke "main.clj" 324]
  [clojure.main$main doInvoke "main.clj" 422]
  [clojure.lang.RestFn invoke "RestFn.java" 397]
  [clojure.lang.Var invoke "Var.java" 375]
  [clojure.lang.AFn applyToHelper "AFn.java" 152]
  [clojure.lang.Var applyTo "Var.java" 700]
  [clojure.main main "main.java" 37]]}
user=>


 Comments   
Comment by Alex Miller [ 22/Dec/15 4:09 PM ]

dupe of and fixed by ASYNC-152

Comment by Nicola Mometto [ 22/Dec/15 6:00 PM ]

Just for the record, this is neither a core.async nor a tools.analyzer bug.
It turns out that re-evaluating a defmulti expression completely nukes any metadata on that defmulti, breaking tools.analyzer's scheduler since it relies on that metadata to order the passes.

Comment by Nicola Mometto [ 22/Dec/15 6:08 PM ]

Alex Miller I'm reopening this, pending an assessment on CLJ-1870.
While it is true that the ASYNC-154 patch fixed this specific NPE, `(require :reload-all)` will still break things since as explained in the ticked description of CLJ-1870, t.a passess will be ordered randomly

Comment by Alex Miller [ 13/Feb/17 3:19 PM ]

Both ASYNC-152 and CLJ-1870 have now been applied and I don't think we're going to do anything additional with this, so closing.





[ASYNC-155] Preserve loop binding metadata when inside a go block Created: 15/Dec/15  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Completed Votes: 2
Labels: None

Attachments: Text File 0001-ASYNC-155-preserve-loop-binding-metadata.patch    
Patch: Code
Approval: Triaged

 Description   

Description:
Currently this causes a reflection warning because core.async loses the type hint on the binding:

user=> (set! *warn-on-reflection* true)
true
user=> (require '[clojure.core.async :refer [go chan <!]])
nil
user=> (go (loop* [^String foo "foo"](.substring foo 0) (<! (chan)) (recur nil)))
Reflection warning, /tmp/form-init4315251430191485724.clj:1:1 - call to method substring can't be resolved (target class is unknown).
#object[clojure.core.async.impl.channels.ManyToManyChannel 0xcb98635 "clojure.core.async.impl.channels.ManyToManyChannel@cb98635"]

This is a problem since macros like `doseq` expand to similar code and cause reflection warnings

The attached patch preserves that metadata and removes the reflection warning

Patch: 0001-ASYNC-155-preserve-loop-binding-metadata.patch



 Comments   
Comment by Marcus Crestani [ 04/Jan/16 3:17 AM ]

I can confirm that this patch also fixes ASYNC-157. Thanks!

Comment by Marcus Crestani [ 21/Oct/16 7:08 AM ]

Can this patch be included in a next release of core.async?

Comment by Alex Miller [ 13/Feb/17 3:08 PM ]

Can we get a better example in the ticket? This one seems broken.

Comment by Nicola Mometto [ 13/Feb/17 3:13 PM ]

Fixed the example, I omitted by accident a call to (chan) while copy pasting from the repl

Comment by Alex Miller [ 13/Feb/17 3:20 PM ]

Why are we using loop* in the example?

Comment by Nicola Mometto [ 13/Feb/17 3:23 PM ]

No particular reason, `loop` would manifest the same issue aswell. I don't remember the details but I think I got to this minimal repro case by macroexpanding a doseq form and reducing the code to this, hence why `loop*` instead of `loop`

Comment by Alex Miller [ 13/Feb/17 3:24 PM ]

gotcha, thx

Comment by Alex Miller [ 13/Feb/17 3:24 PM ]

Applied





[ASYNC-70] documentation of thread macro should include behavior of nil (closes the channel) Created: 15/May/14  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Howard Lewis Ship Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: reader
Environment:

0.1.278.0


Attachments: Text File async-70-patch.1.txt    
Patch: Code

 Description   

I needed the ability to invoke some code in a thread, and have the channel close if nil was returned.

Digging though the code, I discovered it already does this, but it is no documented in the docstring.

I'll supply a patch shortly.



 Comments   
Comment by Alex Miller [ 23/Jun/14 11:15 AM ]

The thread docstring says: "Returns a channel which will receive the result of the body when completed." The special case of a null return value is actually handled by ignoring it (because you are not allowed to explicitly put nils on a channel). The channel is closed on completion regardless. I'm not sure I get what needs to be added here and no patch, so closing. Reopen if there is a concrete suggestion to evaluate.

Comment by Howard Lewis Ship [ 14/Nov/14 10:41 AM ]

It's a tiny little patch. DRY is great for code, less so for docs!

Comment by Alex Miller [ 13/Feb/17 3:27 PM ]

Different smaller docstring change applied in 73afa79.





[ASYNC-123] Channel operations fail in for comprehension. Created: 25/May/15  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Christian Weilbach Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None
Environment:

[org.clojure/clojure "1.6.0"]
[org.clojure/core.async "0.1.346.0-17112a-alpha"]



 Description   
(<!! (go (for [a (<! (go [1 2 3]))]
           a)))
;=> (1 2 3)

works fine. But:

(go (for [a [1 2 3]
          :let [b (<! (go a))]]
      b))
java.lang.IllegalArgumentException
   No method in multimethod '-item-to-ssa' for dispatch value: :fn

                  MultiFn.java:  160  clojure.lang.MultiFn/getFn
                  MultiFn.java:  227  clojure.lang.MultiFn/invoke
                ioc_macros.clj:  492  clojure.core.async.impl.ioc-macros/item-to-ssa
                ioc_macros.clj:  547  clojure.core.async.impl.ioc-macros/let-binding-to-ssa/fn
                ioc_macros.clj:  122  clojure.core.async.impl.ioc-macros/all/fn/fn
               ArrayChunk.java:   58  clojure.lang.ArrayChunk/reduce
                 protocols.clj:   98  clojure.core.protocols/fn
                 protocols.clj:   19  clojure.core.protocols/fn/G
                 protocols.clj:   31  clojure.core.protocols/seq-reduce
                 protocols.clj:   54  clojure.core.protocols/fn
                 protocols.clj:   13  clojure.core.protocols/fn/G
                      core.clj: 6289  clojure.core/reduce
                ioc_macros.clj:  120  clojure.core.async.impl.ioc-macros/all/fn
                ioc_macros.clj:  554  clojure.core.async.impl.ioc-macros/eval22522/fn/fn
                ioc_macros.clj:  600  clojure.core.async.impl.ioc-macros/eval22585/fn/fn
                ioc_macros.clj:  806  clojure.core.async.impl.ioc-macros/parse-to-state-machine/fn
                ioc_macros.clj:   80  clojure.core.async.impl.ioc-macros/get-plan
                ioc_macros.clj:  802  clojure.core.async.impl.ioc-macros/parse-to-state-machine
                ioc_macros.clj: 1066  clojure.core.async.impl.ioc-macros/state-machine
                     async.clj:  384  clojure.core.async/go
                   RestFn.java:  442  clojure.lang.RestFn/invoke
                      Var.java:  388  clojure.lang.Var/invoke
                      AFn.java:  160  clojure.lang.AFn/applyToHelper
                      Var.java:  700  clojure.lang.Var/applyTo
                 Compiler.java: 6552  clojure.lang.Compiler/macroexpand1
                 Compiler.java: 6630  clojure.lang.Compiler/analyzeSeq
                 Compiler.java: 6445  clojure.lang.Compiler/analyze
                 Compiler.java: 6406  clojure.lang.Compiler/analyze
                 Compiler.java: 3719  clojure.lang.Compiler$InvokeExpr/parse
                 Compiler.java: 6646  clojure.lang.Compiler/analyzeSeq
                 Compiler.java: 6445  clojure.lang.Compiler/analyze
                 Compiler.java: 6406  clojure.lang.Compiler/analyze
                 Compiler.java: 5782  clojure.lang.Compiler$BodyExpr$Parser/parse
                 Compiler.java: 5217  clojure.lang.Compiler$FnMethod/parse
                 Compiler.java: 3846  clojure.lang.Compiler$FnExpr/parse
                 Compiler.java: 6642  clojure.lang.Compiler/analyzeSeq
                 Compiler.java: 6445  clojure.lang.Compiler/analyze
                 Compiler.java: 6700  clojure.lang.Compiler/eval
                 Compiler.java: 7130  clojure.lang.Compiler/load
                          REPL:    1  geschichte.p2p.hooks/eval32348
                 Compiler.java: 6703  clojure.lang.Compiler/eval
                 Compiler.java: 6666  clojure.lang.Compiler/eval
                      core.clj: 2927  clojure.core/eval
                      main.clj:  239  clojure.main/repl/read-eval-print/fn
                      main.clj:  239  clojure.main/repl/read-eval-print
                      main.clj:  257  clojure.main/repl/fn
                      main.clj:  257  clojure.main/repl
                   RestFn.java: 1523  clojure.lang.RestFn/invoke
        interruptible_eval.clj:   67  clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn
                      AFn.java:  152  clojure.lang.AFn/applyToHelper
                      AFn.java:  144  clojure.lang.AFn/applyTo
                      core.clj:  624  clojure.core/apply
                      core.clj: 1862  clojure.core/with-bindings*
                   RestFn.java:  425  clojure.lang.RestFn/invoke
        interruptible_eval.clj:   51  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
        interruptible_eval.clj:  183  clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
        interruptible_eval.clj:  152  clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn
                      AFn.java:   22  clojure.lang.AFn/run
       ThreadPoolExecutor.java: 1145  java.util.concurrent.ThreadPoolExecutor/runWorker
       ThreadPoolExecutor.java:  615  java.util.concurrent.ThreadPoolExecutor$Worker/run
                   Thread.java:  745  java.lang.Thread/run

Possibly this is due to the function boundaries of go-blocks, but I think it would be nice if this would work similar to the binding for `a`. I have basically one big for-comprehension to map a highly nested seq and rewriting it will make the code much more verbose. Note that I know that I cannot execute channel ops inside the body of the for-comprehension due to the function boundaries in lazy seqs. This is no problem, but I cannot fix the for-comprehension bindings easily.
I played around with extending the -item-to-ssa multimethod, but some pointers of how to fix it properly would be nice. Then I could try to implement a patch.



 Comments   
Comment by Christian Weilbach [ 14/Jun/15 9:11 AM ]

This is actually a problem for many more cases, only a take operation in the first binding works, because the for-comprehension macro in core.clj wraps every following binding in a lazy-seq. The best fix to me seemed to be a custom version of the for-comprehension macro.

I have simplified the macro to remove lazyness and rewritten it with go-loops. This works fairly well, but it is eager and channel operations are sideeffects, so channels representing constants on which iteration happens repeatedly should be put in an immutable collection before (e.g. let binding around the comprehension).

https://github.com/ghubber/geschichte/blob/c57bacdcf8e3335d17dc370941384c559ae80373/src/cljx/geschichte/go_for.cljx#L25

Comment by Christian Weilbach [ 18/Oct/15 12:40 PM ]

Can be closed, is fixed with go-for for me. The irritation came from the first binding working as a channel op, while nested ones are wrapped in lazy-seq fns.

Comment by Alex Miller [ 13/Feb/17 4:17 PM ]

closed at op's request





[ASYNC-32] onto-chan retains head of input sequence causing OutOfMemoryError Created: 06/Nov/13  Updated: 14/Feb/17  Resolved: 14/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Brian Lubeski Assignee: Unassigned
Resolution: Duplicate Votes: 3
Labels: memory
Environment:

org.clojure/core.async 0.1.242.0-44b1e3-alpha


Attachments: File patch.clj    
Patch: Code
Approval: Triaged

 Description   
(require '[clojure.core.async :as a])
(let [c (a/chan)]
  (a/onto-chan c (iterate inc 0))
  (while true
    (a/<!! c)))

onto-chan is holding on to the head of the input sequence as it is unfolded, resulting in an (eventual) OutOfMemoryError.

I've attached a diff showing changes I made to onto-chan that fixed the problem for me.



 Comments   
Comment by Colin Taylor [ 07/Oct/14 7:13 PM ]

Just to note, to-chan uses onto-chan so is similarly affected.
We ran into this, Brian's patch worked fine.

Comment by Alex Miller [ 10/Aug/15 3:22 PM ]

This seems like a viable change, but the patch needs a better test (even if not in the patch) and to be properly formatted for git apply (per http://dev.clojure.org/display/community/Developing+Patches).

Comment by Brian Lubeski [ 11/Aug/15 12:00 AM ]

This issue might be caused by ASYNC-138.

Comment by Nicola Mometto [ 15/Dec/15 6:12 PM ]

The fix for ASYNC-138 should fix this issue aswell and is more general

Comment by Alex Miller [ 14/Feb/17 10:35 AM ]

Duplicate of ASYNC-138





[ASYNC-4] Record literals become ordinary maps Created: 15/Jul/13  Updated: 14/Feb/17  Resolved: 14/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Alex Miller Assignee: Unassigned
Resolution: Not Reproducible Votes: 0
Labels: None
Environment:

CLJS


Approval: Triaged

 Description   
(require '[clojure.core.async :refer (<!! go)])
(defrecord Foo [x])
(def f (Foo. 4))
(<!! (go f))
;; => #user.Foo{:x 4}
;; OK

(<!! (go #clojure.core.async.Foo{:x 4}))
;; CLJ: => #user.Foo{:x 4}   ;; expected
;; CLJS => {:x 4}            ;; wrong

Approach: Query the analyzer to know if we have a record or not.

(Copied from GitHub issue #13 - https://github.com/clojure/core.async/issues/13)



 Comments   
Comment by Ghadi Shayban [ 03/Aug/13 2:08 PM ]

0c6e663493 contains a fix on the Clojure side, would appreciate help porting to cljs.

Comment by David Nolen [ 08/Aug/13 8:35 AM ]

I think on the ClojureScript we'll have to query the analyzer to know if we have a record or not.

Comment by Alex Miller [ 14/Feb/17 10:49 AM ]

Not reproducible





[ASYNC-143] Assert that fixed buffers must have size > 0 Created: 18/Aug/15  Updated: 14/Feb/17  Resolved: 14/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Alex Miller Assignee: Unassigned
Resolution: Completed Votes: 5
Labels: None

Attachments: Text File async-143.patch    
Patch: Code
Approval: Triaged

 Description   

(chan 0) is invalid (and is not the same thing as an unbuffered (chan)).

Approach: Add an assertion to throw on (chan 0). I found based on some failing tests that one place this can come up is in to-chan, which creates a buffer sized to the collection (0). The patch also changes to-chan to return an empty, closed chan if the collection is of size 0.

Patch: async-143.patch



 Comments   
Comment by Alexander Yakushev [ 16/Aug/16 3:24 AM ]

Bump! I was quite surprised today by this.

Besides, the wording could be changed to something like "If a transducer is supplied a non-zero length buffer must be specified."

Comment by Alex Miller [ 14/Feb/17 11:01 AM ]

Applied





[ASYNC-187] Tag metadata is lost in local closed over by a loop Created: 23/Feb/17  Updated: 23/Feb/17  Resolved: 23/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: typehints

Attachments: Text File 0001-ASYNC-187-preserve-type-info-of-locals.patch    
Patch: Code
Approval: Ok

 Description   

This seems related to ASYNC-155, a small repro:

(defn foo []
  (a/go
    (let [^String a (identity "foo")]
      (loop []
        (.substring a 1 2)
        (a/<! nil)
        (recur)))))
Reflection warning, NO_SOURCE_PATH:23:17 - call to method substring can't be resolved (target class is unknown).

This bug affects all version of core.async, but it's getting triggered more now that the patch for ASYNC-138 applies a lexical transformation that makes code look like this, thus hitting this bug more often

Approach: The approach is the same used for ASYNC-155, applied to :let binding

Patch: 0001-ASYNC-187-preserve-type-info-of-locals.patch



 Comments   
Comment by Alex Miller [ 23/Feb/17 12:55 PM ]

Applied for next release.





[ASYNC-186] NPE when `go` closes over a local variable bound to nil Created: 23/Feb/17  Updated: 23/Feb/17  Resolved: 23/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: regression

Attachments: Text File 0001-ASYNC-186-Apparently-Compiler.java-can-return-true-f.patch    
Patch: Code and Test
Approval: Ok

 Description   

This throws a NPE after ASYNC-138

(defn foo [x]
  (let [y nil]
    (a/go)))

Analysis: Compiler.java exhibits a quircky behaviour where for a local bound to nil, it'll return `true` for `lb.hasJavaClass()` but `lb.getJavaClass()` will return `nil`, which causes a NPE when we invoke `lb.getJavaClass().getName()`

user> (defmacro foo []
        (doseq [[l ^clojure.lang.Compiler$LocalBinding lb] &env]
          (println (.hasJavaClass lb) (.getJavaClass lb))))
#'user/foo
user> (let [a nil] (foo))
true nil

Approach:
Don't assume `.getJavaClass` will return non-nil when `hasJavaClass` returns true

Patch: 0001-ASYNC-186-Apparently-Compiler.java-can-return-true-f.patch



 Comments   
Comment by Alex Miller [ 23/Feb/17 9:11 AM ]

Applied for next build.





[ASYNC-188] Properly pop `let` locals binding Created: 23/Feb/17  Updated: 23/Feb/17  Resolved: 23/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-ASYNC-188-properly-pop-locals-binding.patch    

 Description   

ASYNC-187 incorrectly popped the locals stack, this patch fixes it



 Comments   
Comment by Alex Miller [ 23/Feb/17 12:56 PM ]

Applied for next release.





[ASYNC-53] Definition of UnblockingBuffer Protocol makes core.async incompatible with clojure 1.4 Created: 03/Feb/14  Updated: 23/Jun/14  Resolved: 23/Jun/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Kuldeep Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None

Attachments: Text File 0001-Compatibility-with-1.4.patch    
Patch: Code

 Description   

An empty protocol could not be compiled with clojure 1.4. I have attached a patch to show the problem locations.

Thanks



 Comments   
Comment by Alex Miller [ 23/Jun/14 8:53 PM ]

core.async is only intended to be compatible with Clojure 1.5.1+.





[ASYNC-82] Channels should accept Metadata Created: 02/Aug/14  Updated: 03/Aug/14  Resolved: 03/Aug/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Alexander Kiel Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Currently channels do not implement IObj and so do not accept metadata. My use case is no annotate channels with a name so that I can print out its name after an alts!.



 Comments   
Comment by Ghadi Shayban [ 03/Aug/14 10:09 PM ]

For efficiency reasons, channels are plain deftypes, which don't accept metadata.

Since channels are identities, they can be used in a map or set, and you can store the names or info out-of-band. May I suggest the following pattern:

(let [in (chan)
      out (chan)

      names {in :request
             out :response}
      val (rand-int 50)
      [v ch] (alts! [in [out val]])]
  (names ch))




[ASYNC-81] Spurious Closure warnings when using new ClojureScript dependency Created: 01/Aug/14  Updated: 04/Aug/14  Resolved: 04/Aug/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: David Nolen Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

Closure now emits a warning if core.async generates code with dead branches.



 Comments   
Comment by Ghadi Shayban [ 03/Aug/14 10:10 PM ]

David, do you have a minimal reproducing example?

Comment by David Nolen [ 04/Aug/14 7:57 AM ]

Sorry for not looking into this more closely first. It turns out the pattern of (assert nil "text") is the culprit - it compiles to a JavaScript if statement with null as the test and null as the success statement. We should drop this pattern for a simple throw in my opinion.

Comment by David Nolen [ 04/Aug/14 12:37 PM ]

this is fixed in master https://github.com/clojure/core.async/commit/41262e26b4d2b3070d23f927c25f585d9dc48951. The other dead code warnings from Closure needed to addressed in the ClojureScript compiler itself which is also resolved https://github.com/clojure/clojurescript/commit/8013f0fd0a7803c01efca90e757d316c0a1e1ec0





[ASYNC-89] mistake in core.async put! docstring Created: 02/Sep/14  Updated: 02/Sep/14  Resolved: 02/Sep/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Bruce Adams Assignee: Bruce Adams
Resolution: Completed Votes: 0
Labels: None

Attachments: File docstring.diff    
Patch: Code
Approval: Vetted

 Description   

In [1], correct statement should be "passing false iff port is already closed" instead of current "passing true iff port is already closed".

Current behavior is that put callback fn gets true if a channel is not already closed:

user=> (require '[clojure.core.async :as async])
nil
user=> (def c (async/chan 1))
#'user/c
user=> (async/put! c :foo #(println "got " %))
got  true
true
user=> (async/close! c)
nil
user=> (async/put! c :foo #(println "got " %))
got  false
false

From Jozef Wagner in https://groups.google.com/forum/#!topic/clojure-dev/zduW2jMndZ4

[1] https://github.com/clojure/core.async/blob/422f8b25f0c4d5e3aea5113436c735e553422be7/src/main/clojure/clojure/core/async.clj#L140






[ASYNC-31] put! does not throw on closed channel Created: 02/Nov/13  Updated: 02/Sep/14  Resolved: 02/Sep/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Chris Perkins Assignee: Unassigned
Resolution: Duplicate Votes: 1
Labels: None
Environment:

rev 1bf8cf4



 Description   

The docstring of put! says "Will throw if closed". However, put!-ing to a closed channel appears to succeed, and even calls the supplied callback.

I'm not sure which is incorrect - the behavior or the docstring (or my intepretation of it) - but it does appear that the implementation of mult is expecting an exception from put!, in order to do cleanup.



 Comments   
Comment by Justin Balthrop [ 10/Feb/14 4:53 PM ]

The doc string for put! no longer says "Will throw if closed" for clojure.core.async, though it does still say this for cljs.core.async (and doesn't seem to work).

It looks like Rich started switching put! to return true unless the channel is closed in cf8dc1bf207e646c14b2bf44763737fcb5f08c78. The docstring reflects this change, but from my testing, put! still always returns nil.

Comment by Sung Pae [ 02/Apr/14 3:25 PM ]

Since this is likely a docstring mismatch, I'd like to add that the docstring for clojure.core.async/put states:

Asynchronously puts a val into port, calling fn1 (if supplied) when complete, passing true iff port is already closed.

fn1 is passed `false` when the port is closed, not `true`.

Comment by Alex Miller [ 02/Sep/14 9:39 AM ]

Docstring addressed with ASYNC-89





[ASYNC-38] keep</> instead of map</> Created: 18/Nov/13  Updated: 02/Sep/14  Resolved: 02/Sep/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Leon Grapenthin Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: documentation, enhancement, errormsgs


 Description   

One problem with using map< is when the supplied function returns nil. In such case (using the latest implementation from core.async [org.clojure/core.async "0.1.256.0-1bf8cf-alpha"]) one can take nil from a channel created with map<. This is otherwise only possible with closed channels. Putting nil on a channel normally throws an IllegalArgumentException.

With the current implementation of map< it is not possible to determine whether the source-channel was closed or the supplied function returned nil.

Notice that putting onto a channel created with map> throws an IllegalArgumentException when the supplied function returns nil as if you would put nil onto a channel.

My proposal is to add keep</> (where nil values returned from the supplied function are ignored and nothing is put) to the core library or to implement map</> as keep</> since having a real map</> instead of keep</> hardly makes sense when nil is not permitted anyways.



 Comments   
Comment by Leon Grapenthin [ 24/Apr/14 3:44 AM ]

It is still an issue in "0.1.278.0-76b25b-alpha" that you can only use impl.protocols/closed? to consistently determine whether a channel created with map</> was closed - if nil is one of your predicates return values.

Of course, you could use a predicate that never returns nil. But what should be the benefit of map</> being able to magically pass nil while everything else isn't?

Comment by Alex Miller [ 02/Sep/14 9:43 AM ]

All of the transformation functions (like map<) are deprecated and will go away to be replaced with applying transducers to channels.





[ASYNC-50] Add bang(!) to the names of channel ops with side effects Created: 16/Jan/14  Updated: 02/Sep/14  Resolved: 02/Sep/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Jozef Wagner Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Some channel ops immediatelly change the given channel, thus they have side effects. This include async/map, filter<, remove<, mapcat<, pipe, split, reduce, onto-chan, etc. All 'mutating' basic channel operations have bang at the end of their name (<Unable to render embedded object: File (, >) not found., alt!, ...). If we want to be consistent with this, bang should be added to every channel function which has side effects.



 Comments   
Comment by Alex Miller [ 02/Sep/14 9:56 AM ]

Rich named these and there are no plans to change them.





[ASYNC-88] Add Sonatype repository info to README for unreleased library Created: 27/Aug/14  Updated: 02/Sep/14  Resolved: 02/Sep/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Bridget Hillyer Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: documentation


 Description   

It could be confusing for those not very familiar with Leiningen, Maven, etc. that there is a separate way to obtain SNAPSHOT versions of libraries vs. Released versions of libraries.

I believe an easy fix would be to have the following information directly in the README of unreleased contrib libraries (of which core.async is one):

To use Clojure and contrib library SNAPSHOTS in your Leiningen project, add the following to your project.clj:

:repositories {"sonatype-oss-public" "https://oss.sonatype.org/content/groups/public/"}



 Comments   
Comment by Alex Miller [ 02/Sep/14 9:50 AM ]

Done.

Comment by Alex Miller [ 02/Sep/14 10:02 AM ]

Actually, I have un-done this for core.async as we don't ever release SNAPSHOT versions of core.async, so it's thus a bit confusing. The canonical place we point people for this repo setup info is:

http://dev.clojure.org/display/community/Maven+Settings+and+Repositories

Comment by Bridget Hillyer [ 02/Sep/14 10:11 AM ]

I realized that this does not affect core.async after I made this ticket. Maybe something was down that day so I couldn't get the canonical release? So, right, this is not valid for core.async. But it would be for other (contrib?) libraries that do get SNAPSHOTs released.

The setup info that you pointed out:
http://dev.clojure.org/display/community/Maven+Settings+and+Repositories
would probably be useful from a usability standpoint in the READMEs themselves, including core.async.





[ASYNC-59] Channel returned by cljs.core.async/map> is missing protocol method Channel.closed? Created: 08/Mar/14  Updated: 10/Sep/14  Resolved: 02/Sep/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Kevin Neaton Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: bug, patch
Environment:

[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-2173"]
[org.clojure/core.async "0.1.278.0-76b25b-alpha"]


Attachments: Text File 0001-Fixed-map-by-including-impl.-for-closed.patch    
Patch: Code

 Description   

E.g.

(let [ch (->> (chan) (map> inc) (filter> even?))]
  (doseq [i (range 10)] (put! ch i)))

When filter> checks to see if the channel returned by map> is closed?, this code fails because the channel returned by map> does not implement the Channel.closed? protocol method.



 Comments   
Comment by Alex Miller [ 02/Sep/14 9:54 AM ]

map> and filter> have been deprecated and will be removed in a future release. They have been replaced with applying transducers to a channel which is now available.

Comment by Kevin Neaton [ 10/Sep/14 9:08 AM ]

Great, thanks for the update.





[ASYNC-95] Tranducers and unbuffered channels Created: 12/Oct/14  Updated: 16/Oct/14  Resolved: 16/Oct/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Nguyễn Tuấn Anh Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Currently buffered channels are required to use transducers.

Is this a limitation of the current implementation, or was it a design decision?

In the Javascript port of core.async (js-csp), we have been experimenting with a different approach:

  • The step function takes the whole channel as its "result" parameter, instead of just the buffer. It also handles committing pending active takes. This allows values to go straight from puts to takes when needed (subjecting to the transformation), allowing unbuffered channels to use transducers.
  • To handle "expanding" transducers like "cat", a separate overflow buffer is used instead of allowing the fixed buffer to grow on overflow.

In short, "add" would do this:

  • Commit the first pending active taker it finds, giving it the value
  • Put the value into the normal buffer if there is one, and if it is not full
  • Put the value into the overflow buffer

We haven't thoroughly tested this approach yet, but it seems like it would work well, except for the overhead of an overflow buffer for every channel, which can be fixed by creating it on-demand.

This is the discussion we had: https://github.com/ubolonton/js-csp/issues/7#issuecomment-57940050
Is this approach reasonable? Are there other potential pitfalls we missed?



 Comments   
Comment by David Nolen [ 14/Oct/14 5:54 AM ]

As far as I know it was a design decision. Given that I'm not sure what the purpose of this ticket is. Questions about implementation are probably best discussed on the clojure-dev Google Group before creating tickets. I'm inclined to close this unless a real problem is specified.

Comment by Nguyễn Tuấn Anh [ 16/Oct/14 11:19 AM ]

Thanks. I'm unfamiliar with the workflow. I'm going to post this to that group.





[ASYNC-83] Taking from channels in anonymous functions inside go-loops does not work Created: 05/Aug/14  Updated: 04/Nov/14  Resolved: 04/Nov/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Joel Knighton Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

latest core.async release, latest core.async built from source



 Description   

This seems to be related/comparable to the issue posted on this mailing-list thread:
https://groups.google.com/forum/#!topic/clojure/vtvk7warLE4

Minimal testcases to reproduce:

(def ch (chan))

(go-loop []
(>! ch "test"))

(go-loop []
(println (<! ch))) ;;prints "test"

(future (println (<!! ch))) ;;prints "test"

(future (println (#(<!! ch)))) ;;prints "test"

(go-loop []
(println (#(<! ch)))) ;;CompilerExpection java.lang.IllegalArgumentException:
;; No method in multimethod '-item-to-ssa' for dispatch
;; value :fn



 Comments   
Comment by Joel Knighton [ 05/Aug/14 12:41 PM ]

It appears the go-loop isn't even necessary -
(go (println (#(<! ch)))) reproduces the issue.

Comment by Kevin Downey [ 05/Aug/14 1:39 PM ]

I think this is expected behaviour, the go transformation macro doesn't attempt to descending in to called functions to transform their bodies, since their bodies are not transformed the <! and >! operators, which do not work in untransformed code, do not work.

the following which explicitly transforms the body of the inner function using the go macro should work:

(go (println (#(go (<! ch)))))

it will print out a channel though, because the result of (go ...) is a channel that will contain the result of ...

Comment by Joel Knighton [ 05/Aug/14 1:45 PM ]

Okay - thanks for the feedback. This doesn't cause an issue for me, and your explanation makes sense.

Comment by Alex Miller [ 04/Nov/14 4:01 PM ]

Agreed that go macro does not descend into function creation (fn or #() forms). The error could be better in this case but that's logged in a separate ticket.





[ASYNC-57] reify in go macro compile error Created: 20/Feb/14  Updated: 04/Nov/14  Resolved: 04/Nov/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Lijin Liu Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

[org.clojure/clojure "1.5.1"]
[org.clojure/core.async "0.1.267.0-0d7780-alpha"]



 Description   

(go
(reify java.util.Collection
(add [this o]
(println o)
(println this)
true)))

clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to resolve symbol: this in this context



 Comments   
Comment by Ghadi Shayban [ 22/Apr/14 9:55 AM ]

Reassigning to minor. The go macro will obviously not rewrite parking ops inside the reify. Lifting the reify into a var is a decent workaround.

Comment by Alex Miller [ 04/Nov/14 4:02 PM ]

Not supported.





[ASYNC-106] A unit test in ioc_macros_test.clj tests nothing Created: 10/Nov/14  Updated: 06/Jul/15  Resolved: 06/Jul/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Andy Fingerhut Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Approval: Ok

 Description   

I am not sure what it should be doing, but this test in file ioc_macros_test.clj is always true, because it is of the form (is (= x)), which always passes:

(testing "lazy-seqs in bodies"
    (is (= (runner
            (loop []
              (when-let [x (pause 10)]
                (pause (vec (for [i (range x)]
                              i)))
                (if-not x
                  (recur))))))))


 Comments   
Comment by Alex Miller [ 06/Jul/15 4:08 PM ]

Committed a fix.





[ASYNC-135] alt! with a closed channel will still return results from the closed channel Created: 27/Jul/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Daniel Compton Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

I'm not sure if this is a documentation bug, or an implementation bug, but alt! will always return nil from chan1 in the following code.

(let [chan1 (async/chan 10)
      chan2 (async/chan 10)]
  (async/close! chan1)
  (async/>!! chan2 "run")
  (async/go (async/alt! :priority true

               chan1 ([val] (println "chan1" val))

               chan2 ([val] (println "chan2" val)))))
;; => chan1 nil

The intent of my code was to alt! over the two channels, preferring chan1, but running chan2 if chan1 has nothing to take. However changing this would interfere with using timeout channels in an alt!, so it seems like documenting this might be the best fix?



 Comments   
Comment by Leon Grapenthin [ 30/Jul/15 3:25 AM ]

This is expected. Takes from closed channels return nil. The behavior is documented in the docstring of close!





[ASYNC-139] inconsistent thread pool in async/pipeline-blocking function Created: 15/Aug/15  Updated: 16/Aug/15  Resolved: 15/Aug/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Miro Kubicek Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

platform non-specific


Attachments: PNG File pipeline diff screenshot .png    
Patch: Code

 Description   

Hi there,
in pipeline* function for the :blocking processing there is no loop within each thread - while for the async processing there is always a go-loop [] which can be re-written as (go (loop []..., for sync processing there is only "thread" macro with no loop in it and with a recur call at the end. I would assume recur without a loop jumps back to a given defn. Why is there no loop? If a thread is instantiated then it should continue doing its work.

Apologies if I am missing something and the recur really jumps back to the thread macro.

To illustrate this in the code - basically I would expect that the following:

pipeline*
:blocking (thread
                           (let [job (<!! jobs)]
                             (when (process job)
                              (recur))))

Should look more like this:

pipeline*
:blocking (thread (loop[]
                           (let [job (<!! jobs)]
                             (when (process job)
                              (recur)))))

Even if the recur without loop jumps back to the thread macro I would wonder whether it might lead to some unexpected behavior (each thread being recreated after every iteration) and if it jumps elsewhere it might lead to the thread halting after only one iteration is performed.

My (closed) pull request for this fix:
https://github.com/clojure/core.async/pull/47/commits

Cheers
Miro



 Comments   
Comment by Alex Miller [ 15/Aug/15 4:09 PM ]

thread is a macro that nests the body inside an anonymous fn, which serves as a recur target. Thus the code is working as expected.

Comment by Miro Kubicek [ 16/Aug/15 1:25 AM ]

Thanks for the explanation Alex!





[ASYNC-146] poll! still not being supported Created: 18/Sep/15  Updated: 18/Sep/15  Resolved: 18/Sep/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Miro Kubicek Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: maven, poll!, release


 Description   

In the last releases (0.1.346.0-17112a-alpha and older) poll! is still not supported even though it has been implemented for awhile (I can see it in the trunk and it seemed to be implemented as a part of ASYNC-104 in Feb).
If I try to use poll! with the latest version from maven repo I get "java.lang.IllegalAccessError: poll! does not exist".
Further checking maven repo history it even seems that the latest release is from 22-Sep-2014 - i.e. a year ago? Or is it a glitch? I understand this is an alfa, but especially for that reason it would be great if there were newer "nightly builds" / versions available in maven/leiningen.
Would getting the trunk (master) code directly from git be a suggested approach? (as opposed to using maven/leiningen)



 Comments   
Comment by Alex Miller [ 18/Sep/15 10:32 AM ]

I'm closing this as it's really a question not a ticket.

We are working towards a release in the near future that will include this functionality. Unfortunately, the existing build setup for this particular library does not make it easy to release interim snapshots - you are welcome to build your own from master if you like.





[ASYNC-6] alts! assumes nth works on ports argument Created: 15/Jul/13  Updated: 14/Oct/15  Resolved: 27/Sep/13

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Brandon Bloom Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None


 Description   

The docstring for alts! reads:

ports is a set of channel endpoints, which
can be either a channel to take from or a vector of
[channel-to-put-to val-to-put], in any combination.

However, trying to use an actual set yields the following exception:

java.lang.UnsupportedOperationException: nth not supported on this type: PersistentHashSet



 Comments   
Comment by Brandon Bloom [ 07/Aug/13 2:32 PM ]

Discussed at length in IRC on Aug 7th: http://www.raynes.me/logs/irc.freenode.net/clojure/2013-08-07.txt

Comment by Rich Hickey [ 07/Aug/13 9:28 PM ]

The documentation should be changed. alts requires an efficiently nth-able collection (e.g. a vector), else it will be slow.

https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async.clj#L183

If CLJS supports nth on sets it is broken.

Comment by Brandon Bloom [ 07/Aug/13 9:52 PM ]

> alts requires an efficiently nth-able collection

Is that the case? Or does alts actually only require efficiently sampling a single element from a collection?

Efficient nth is a reasonable proxy, since the only choice we have for randomness is rand-int. However, one could imagine a CollSample protocol that would allow efficient random choice leveraging data-structure-specific knowledge, much as CollReduce works. Given the world as it exists now, I agree that this is a doc bug.

> If CLJS supports nth on sets it is broken.

That's the conclusion we came to in IRC. David quickly fixed this:
https://github.com/clojure/clojurescript/commit/a113b08a8c2811b0590cc6a36b2e9e5adc1c4c1e

Comment by Timothy Baldridge [ 27/Sep/13 8:47 AM ]

fixed in master

Comment by Daniel Compton [ 14/Oct/15 5:30 PM ]

For those reading this in the future, this was fixed by changing the docstring to use vector instead of set. https://github.com/clojure/core.async/commit/ca633479f51481f4aee40b4d60120484839d20c6





[ASYNC-152] Reflection warning when binding received values to names. Created: 20/Nov/15  Updated: 22/Dec/15  Resolved: 22/Dec/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Marcus Crestani Assignee: Nicola Mometto
Resolution: Completed Votes: 0
Labels: None
Environment:

OS X 10.11.1
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
[org.clojure/clojure "1.7.0"]
[org.clojure/core.async "0.2.374"]


Attachments: Text File 0001-ASYNC-152-disable-t.a.jvm-s-warn-on-reflection-pass.patch    
Approval: Vetted

 Description   

After upgrading core.async in our project to 0.2.374 (we came
from 0.1.346.0-17112a-alpha), we now see many reflection warnings
that we did not see with the old version.

Here is a simple example code to reproduce the typical reason for
the warning:

(ns dummy
  (:require [clojure.core.async :as async]))

(defn dummy-1
  [ch]
  (async/go-loop []
    (let [msg (async/<! ch)]
      (if (= :close msg)
        (async/close! ch)
        (recur)))))

We see:

Reflection warning: dummy.clj:8:11 - call to static method equiv on clojure.lang.Util cannot be resolved

The warning is about (= :close msg).

Note that there is no reflection warning when we are not binding
the received value to a name, i.e. (= :close (async/<! ch))
works.

Why do we see these reflection warnings after upgrading?
How can we fix these warning?

Patch:
0001-ASYNC-152-disable-t.a.jvm-s-warn-on-reflection-pass.patch



 Comments   
Comment by Alex Miller [ 20/Nov/15 8:24 AM ]

I have seen some of these as well and I suspect it's most likely due to the more recent tools.analyzer versions. I think there are some useful notes here too, thanks.

I do not currently have any suggestion on how to stop these from happening.

Comment by Nicola Mometto [ 15/Dec/15 5:55 PM ]

Minimal case:

(fn [ch] (go (let* [msg (<! ch)] (= :foo msg)))
Comment by Nicola Mometto [ 15/Dec/15 6:02 PM ]

tools.analyzer.jvm's method matcher seems to be bugged, the reflection warning comes from t.a rather than from clojure, clojure doesn't actually require reflection for this.

This patch simply disables tools.analyzer's warn-on-reflection pass, since the clojure compiler will warn itself if something will reflect

Comment by Alex Miller [ 22/Dec/15 3:43 PM ]

applied





[ASYNC-133] Expose 'closed?' predicate Created: 18/Jul/15  Updated: 12/Feb/16  Resolved: 18/Jul/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Alejandro Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: None


 Description   

It can be useful to, given a channel, use a predicate to know wheter is closed or not. The 'closed?' predicate is currently not public and remains an implementation detail.



 Comments   
Comment by Alex Miller [ 18/Jul/15 11:36 AM ]

Dupe of CLJ-126

Comment by Brandon Bloom [ 12/Feb/16 1:27 PM ]

I think you mean dupe of http://dev.clojure.org/jira/browse/ASYNC-126





[ASYNC-167] Fix docstring for put! and friends Created: 27/Apr/16  Updated: 28/Apr/16  Resolved: 28/Apr/16

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Alan Thompson Assignee: Unassigned
Resolution: Not Reproducible Votes: 0
Labels: docstring, documentation


 Description   

The docstring for `put!` and friends is misleading and incorrect. They repeatedly mention "port" where the user knows only the term "channel".

Also, description of `fn0` is missing & incorrect. The phrase "Will throw if closed" is incorrect. fn0 is called with a single arg, which is `true` upon success and `false` if the channel is closed.



 Comments   
Comment by Alex Miller [ 28/Apr/16 5:23 PM ]

docstring was already updated





[ASYNC-157] Reflection warning with doseq Created: 04/Jan/16  Updated: 17/Jun/16  Resolved: 17/Jun/16

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Marcus Crestani Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: None
Environment:

OS X 10.11.2
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
[org.clojure/clojure "1.7.0"]
[org.clojure/core.async "0.2.374"] and also core.async GIT HEAD, latest commit 6e8b1aa



 Description   

A doseq within a go block that contains some async calls causes a reflection warning.
Here is a simple example:

(ns dummy
  (:require [clojure.core.async :as async]))

(defn dummy
  [ch cs]
  (async/go
    (doseq [c cs]
      (async/>! ch c))))
Reflection warning, /Users/crestani/activegroup/factorylink/dummy.clj:6:3 - call to method nth can't be resolved (target class is unknown).

How can we avoid these warnings?



 Comments   
Comment by Nicola Mometto [ 04/Jan/16 2:53 AM ]

Dupe of ASYNC-155

Comment by Alex Miller [ 17/Jun/16 11:04 AM ]

closing as dupe





[ASYNC-130] Improve put! docstring to mention no more than 1024 pending puts are allowed Created: 21/Jun/15  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Daniel Compton Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: docstring


 Description   

The put! docstring says:

> "Asynchronously puts a val into port, calling fn0 (if supplied) when
complete. nil values are not allowed. Will throw if closed. If
on-caller? (default true) is true, and the put is immediately
accepted, will call fn0 on calling thread. Returns nil."

It would be good if it also mentioned that it can throw if more than 1024 pending puts are already on the channel. It could be something like:

> "Asynchronously puts a val into port, calling fn0 (if supplied) when
complete. nil values are not allowed. Will throw if closed or if there are more than 1024 pending puts. If
on-caller? (default true) is true, and the put is immediately
accepted, will call fn0 on calling thread. Returns nil."



 Comments   
Comment by Alex Miller [ 13/Feb/17 3:53 PM ]

Not going to document this for now as it may change in the future.





[ASYNC-134] async/alts!! with an empty vector throws ArrayIndexOutOfBoundsException Created: 27/Jul/15  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Daniel Compton Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

I'm not sure if this is intended, but this code throws an exception.

(async/alts!! [])
;; => ArrayIndexOutOfBoundsException 1  clojure.core.async/random-array (async.clj:182)

Is this desired behaviour, or is there another way we could represent that this collection is empty? I'm thinking of the pattern where we take from any channel, and recur with that channel removed from the collection until the collection is empty. Perhaps this usage should be discouraged. If it should be discouraged, should it be documented in the docstring?



 Comments   
Comment by Alex Miller [ 28/Jul/15 9:08 AM ]

What would you expect this to do?

Comment by Daniel Compton [ 28/Jul/15 5:20 PM ]

You could return [nil nil]? That's not great either though. Documentation is probably a better fix.

Comment by Alex Miller [ 13/Feb/17 3:52 PM ]

Declining any change for now, may reconsider in future

Comment by Daniel Compton [ 13/Feb/17 4:27 PM ]

Would it be possible to add something to the docstring explaining this behaviour?

Comment by Daniel Compton [ 13/Feb/17 4:41 PM ]

"Declining any change" presumably includes docstrings too, so will leave this.





[ASYNC-113] alt!! should not evaluate the :default expr if a non-default clause is selected Created: 13/Jan/15  Updated: 14/Feb/17  Resolved: 14/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Caleb Spare Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: alt
Environment:

Clojure 1.5.0, core.async 0.1.346.0-17112a-alpha


Approval: Triaged

 Description   

alt!! will always evaluate the expr given in the :default clause. For instance, consider this code:

(require '[clojure.core.async :as async])
(let [c1 (async/chan 1)
      c2 (async/chan 1)]
  (async/alt!!
    [[c1 "a"]] (println "first")
    [[c2 "a"]] (println "second")
    :default (println "default")))

It will print either "first" or "second", but also (always) "default". Reading the documentation, technically it doesn't say whether the non-selected clauses are evaluated (only that the value of the selected expr is returned) but it's certainly not the behavior I would expect.

I haven't checked whether alt! does the same thing as well.



 Comments   
Comment by Daniel Compton [ 27/Jul/15 7:37 PM ]

It looks to me like :default is expected to be a value, not a function, and println is being run as part of evaluating the alt!! expression, not as the return value.

Comment by Alex Miller [ 14/Feb/17 10:46 AM ]

Agreed - re Daniel's comment.





[ASYNC-111] maps are represented different inside and outside of go blocks Created: 27/Dec/14  Updated: 14/Feb/17  Resolved: 14/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Sven Richter Assignee: Unassigned
Resolution: Not Reproducible Votes: 0
Labels: None
Environment:

clojure 1.6.0, clojurescript "0.0-2371", W7, Oracle JDK 8



 Description   

When initializing a state atom with a set "conjuring" a map behaves differently depending of the scope where it happens:

(def state (atom {:transformations []}))
(reset! state {:transformations #{:foo "bar"}})

; throws: Uncaught Error: compare on non-nil objects of different types
(...(go ;some async stuff
(swap! state conj {:name "baz"}))...)

; works
(...(go ;some async stuff)
(swap! state conj {:name "baz"}))

I am not sure if this is a defect at all as maps are not comparable as Tom in the thread stated. However, the fact that it works in one case and does not in the other is weird.
You can find the complete thread here: https://groups.google.com/forum/#!topic/clojurescript/lmvltpa3k8s



 Comments   
Comment by Alex Miller [ 14/Feb/17 10:56 AM ]

Can't repro, don't see a bug.





[ASYNC-185] `thread` prevents clearing of body locals Created: 17/Feb/17  Updated: 23/Feb/17  Resolved: 23/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: memory

Attachments: Text File 0001-ASYNC-185-use-fn-once-for-thread-thunk.patch    
Patch: Code
Approval: Ok

 Description   

`thread` wraps its body in a `(fn [] ~@body)`, it should wrap it in `(^:once fn* [] ~@body)` instead to allow clearing of closed over locals

Patch: 0001-ASYNC-185-use-fn-once-for-thread-thunk.patch



 Comments   
Comment by Alex Miller [ 23/Feb/17 9:16 AM ]

Applied for next release.





[ASYNC-87] Add variant of pipe which accepts mapping fn Created: 24/Aug/14  Updated: 02/Sep/14  Resolved: 02/Sep/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Brandon van Beekum Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

I'd propose something like:

(pipe from to mapping-fn ex-handler)

Currently I am doing the following to patch two channels together with a transform fn:

(defn my-pipe [from to f exh]
(let [map-ch (chan 1 f exh)]
(async/pipe from map-ch)
(async/pipe map-ch to)))



 Comments   
Comment by Alex Miller [ 02/Sep/14 9:16 AM ]

You can do this now with async/pipeline (with concurrent execution, blocking, async, etc):

(async/pipeline 1 to f from)





[ASYNC-105] Remove or correct incorrect type tag on MAX-QUEUE-SIZE Created: 10/Nov/14  Updated: 10/Nov/14  Resolved: 10/Nov/14

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Andy Fingerhut Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: None


 Description   

In this line in file src/main/clojure/clojure/core/async/impl/protocols.clj:

(def ^:const ^int MAX-QUEUE-SIZE 1024)

the int type tag is interpreted by the Clojure compiler as the function clojure.core/int, and thus does not help in avoiding reflection. Suggest removing it, or changing that line to have a correct type tag as follows:

(def ^:const ^{:tag 'int} MAX-QUEUE-SIZE 1024)

Found using Eastwood linter (latest released version 0.1.5 looks for incorrect type tags like this).



 Comments   
Comment by Alex Miller [ 10/Nov/14 12:38 PM ]

Dupe of ASYNC-54





[ASYNC-112] Change wording from transformer to transducer in documentation of deprecated functions Created: 30/Dec/14  Updated: 01/Jan/15  Resolved: 01/Jan/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Erik Assum Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Approval: Ok

 Description   

In the documentation for the deprecated functions in core.async, the wording "transformer" is used instead of "transducer", this should be fixed.

A fix is implemented in https://github.com/clojure/core.async/pull/46



 Comments   
Comment by Alex Miller [ 01/Jan/15 10:07 AM ]

Updated messages to s/transformer/transducer/





[ASYNC-136] Add webinar to presentations section in README.md Created: 30/Jul/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Michiel Borkent Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Add a link to the core.async webinar presented by David Nolen to the presentations section in README.md.
The link is: http://go.cognitect.com/core_async_webinar_recording



 Comments   
Comment by Alex Miller [ 30/Jul/15 8:21 AM ]

Added





[ASYNC-177] Typo in `full?` docstring of the Buffer protocol Created: 14/Sep/16  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: Marcus Spiegel Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File Fix-typo-in-docstring-for-full.patch    
Patch: Code

 Description   

The boolean return value is mixed up in the `full?` function of the Buffer protocol (clj and cljs).



 Comments   
Comment by Alex Miller [ 13/Feb/17 3:39 PM ]

Applied for next release.





[ASYNC-54] MAX-QUEUE-SIZE has a wrong type-hint Created: 11/Feb/14  Updated: 13/Feb/17  Resolved: 13/Feb/17

Status: Closed
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-Fix-MAX-QUEUE-SIZE-type-hint-def-evaluates-the-metad.patch    

 Description   

Since `def` evaluated the metadata on the symbol by design, primitive type hints needs to be quoted to avoid resolving to the homonimous clojure.core function



 Comments   
Comment by Alex Miller [ 23/Jun/14 3:22 PM ]

Actually, I think no hint is needed here at all and it should just be removed. Clojure will just inline a primitive long for the MAX-QUEUE-SIZE where it is used.

Comment by Alex Miller [ 13/Feb/17 4:28 PM ]

Applied patch





[ASYNC-140] transducer not applied with unbuffered channels Created: 17/Aug/15  Updated: 04/Nov/15  Resolved: 18/Aug/15

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: Alex Miller Assignee: Alex Miller
Resolution: Declined Votes: 0
Labels: None

Approval: Triaged

 Description   

Found this while testing some stuff on ASYNC-124.

(require '[clojure.core.async :as a :refer (>!! <!! chan onto-chan)])
(def c (chan 1 (mapcat #(range %))))
(onto-chan c [1 2 3])
(<!! (a/reduce conj [] c))
;; [0 0 1 0 1 2]

(def c (chan 0 (mapcat #(range %))))
(onto-chan c [1 2 3])
(<!! (a/reduce conj [] c))
;; [1 2 3]

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.



 Comments   
Comment by Alex Miller [ 17/Aug/15 5: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.

Comment by Alex Miller [ 18/Aug/15 8:17 AM ]

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

Comment by Alex Nixon [ 04/Nov/15 5:10 PM ]

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?

Comment by Alex Miller [ 04/Nov/15 9:17 PM ]

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.





[ASYNC-10] cljs nested go blocks do not work Created: 18/Jul/13  Updated: 19/Jul/13  Resolved: 19/Jul/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Rich Hickey
Resolution: Completed Votes: 0
Labels: None


 Description   
(go (.log js/console (<! (go 5))))

Results in a channel undefined error



 Comments   
Comment by David Nolen [ 18/Jul/13 5:20 PM ]

This bug is likely due to CLJS-544

Comment by David Nolen [ 19/Jul/13 8:08 AM ]

Not a core.async bug, CLJS-544 was the source of the problem which has been resolved in CljoureScript master.





[ASYNC-11] core.async CLJS support incorrect handling of try/catch Created: 19/Jul/13  Updated: 26/Jul/13  Resolved: 26/Jul/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None

Approval: Accepted

 Description   

core.async is defaulting to lein cljsbuild's ClojureScript instead of more recent versions, this has hidden an error with respect to try/catch. core.async try/catch handling emits code like:

(try ex_0 (do ...)))

This is not correct. ClojureScript requires that you specify the prototype of the error that you want to match. Code like this will result in an error about invalid binding form.

You must emit code that looks like this:

(try js/Error ex_0 (do ...)))


 Comments   
Comment by Timothy Baldridge [ 19/Jul/13 11:48 AM ]

lol, I had this code in place, but removed it because it wouldn't compile correctly. This must have changed in a recent version of CLJS.

Comment by David Nolen [ 19/Jul/13 11:51 AM ]

I commented out the try/catch tests in master. I'll hand this one over to you

Comment by Timothy Baldridge [ 26/Jul/13 8:17 AM ]

Fixed in master





[ASYNC-15] go macro interferes with macros that use &env Created: 30/Jul/13  Updated: 02/Aug/13  Resolved: 02/Aug/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None


 Description   
(defmacro locals-test []
  (if (get &env 'x)
    :works
    :sad-panda))

(let [x 1]
  (locals-test)) ;; :works

(<!! (go
       (let [x 1]
         (locals-test)))) ;; :sad-panda


 Comments   
Comment by Timothy Baldridge [ 02/Aug/13 10:56 AM ]

fixed in : https://github.com/clojure/core.async/commit/9371afbe6b90270f005eb003a08fdcbb9aaa6117





[ASYNC-29] 50 parallel blocking takes in go-blocks as loop-binding or recur argument break go Created: 28/Oct/13  Updated: 29/Oct/13  Resolved: 29/Oct/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Leon Grapenthin Assignee: Rich Hickey
Resolution: Completed Votes: 0
Labels: bug, go, go-macro
Environment:

JVM



 Description   

This problem raises the question whether what the implications are of using <!! and >!! inside of go and whether it is legal.

What if I provide API functions that are using <!! >!! and may be invoked from within go?
Should I then also provide !! and ! versions?

Please evalute this code at the REPL to reproduce the problem: https://www.refheap.com/20225



 Comments   
Comment by Leon Grapenthin [ 29/Oct/13 9:46 AM ]

I'd like to rephrase my question: Do I have to provide {!} and {!!} macros that do the same thing and use {<!} {>!} and {<!!} {>!!} respectively? Would it make sense for core.async to provide a defasync macro that creates those two versions from the same body where you could for example use {<!!!} and {>!!!}, {alts!!!} and so on so that they would be replaced by a postwalk before the macro is defined defined twice with {!} and {!!} appended to the name? Or are there other plans of abstraction? [Quoting symbols because of jira markup]

Comment by Rich Hickey [ 29/Oct/13 9:55 AM ]

You shouldn't be using <!! and >!! in library code. We may at some point be able to detect at runtime their use in go blocks and throw errors, but currently do not.





[ASYNC-34] method calls not correctly handled in go blocks Created: 08/Nov/13  Updated: 09/Nov/13  Resolved: 09/Nov/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Ghadi Shayban
Resolution: Completed Votes: 0
Labels: None


 Description   
(go (. js/console (log "foo")))

Doesn't work.



 Comments   
Comment by Ghadi Shayban [ 09/Nov/13 11:52 PM ]

Fixed on master.





[ASYNC-37] failing set! case Created: 15/Nov/13  Updated: 20/Nov/13  Resolved: 20/Nov/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Ghadi Shayban
Resolution: Completed Votes: 0
Labels: None

Patch: Code and Test

 Description   
(ns example.core
  (:require-macros [cljs.core.async.macros :refer [go]]))

(def foo nil)

(go
  (set! foo "nope"))

Results in the following exception:

clojure.lang.ExceptionInfo: failed compiling file:src/example/core.cljs
                core.clj:4327 clojure.core/ex-info
             compiler.clj:991 cljs.compiler/compile-file
            compiler.clj:1052 cljs.compiler/compile-root
              closure.clj:398 cljs.closure/compile-dir
              closure.clj:437 cljs.closure/eval2663[fn]
              closure.clj:301 cljs.closure/eval2591[fn]
              closure.clj:451 cljs.closure/eval2650[fn]
              closure.clj:301 cljs.closure/eval2591[fn]
              compiler.clj:44 cljsbuild.compiler.SourcePaths/fn
                core.clj:2485 clojure.core/map[fn]
              LazySeq.java:42 clojure.lang.LazySeq.sval
              LazySeq.java:60 clojure.lang.LazySeq.seq
                  RT.java:484 clojure.lang.RT.seq
                 core.clj:133 clojure.core/seq
                 core.clj:617 clojure.core/apply
                core.clj:2514 clojure.core/mapcat
              RestFn.java:423 clojure.lang.RestFn.invoke
              compiler.clj:44 cljsbuild.compiler/cljsbuild.compiler.SourcePaths
             closure.clj:1007 cljs.closure/build
              closure.clj:981 cljs.closure/build
              compiler.clj:58 cljsbuild.compiler/compile-cljs[fn]
              compiler.clj:57 cljsbuild.compiler/compile-cljs
             compiler.clj:158 cljsbuild.compiler/run-compiler
form-init2323732218988862436.clj:1 user/eval3005[fn]
form-init2323732218988862436.clj:1 user/eval3005[fn]
              LazySeq.java:42 clojure.lang.LazySeq.sval
              LazySeq.java:60 clojure.lang.LazySeq.seq
                  RT.java:484 clojure.lang.RT.seq
                 core.clj:133 clojure.core/seq
                core.clj:2780 clojure.core/dorun
                core.clj:2796 clojure.core/doall
form-init2323732218988862436.clj:1 user/eval3005
           Compiler.java:6619 clojure.lang.Compiler.eval
           Compiler.java:6609 clojure.lang.Compiler.eval
           Compiler.java:7064 clojure.lang.Compiler.load
           Compiler.java:7020 clojure.lang.Compiler.loadFile
                 main.clj:294 clojure.main/load-script
                 main.clj:299 clojure.main/init-opt
                 main.clj:327 clojure.main/initialize
                 main.clj:362 clojure.main/null-opt
                 main.clj:440 clojure.main/main
              RestFn.java:421 clojure.lang.RestFn.invoke
                 Var.java:419 clojure.lang.Var.invoke
                 AFn.java:163 clojure.lang.AFn.applyToHelper
                 Var.java:532 clojure.lang.Var.applyTo
                 main.java:37 clojure.main.main
Caused by: clojure.lang.ExceptionInfo: nth not supported on this type: Symbol
                core.clj:4327 clojure.core/ex-info
             analyzer.clj:243 cljs.analyzer/error
            analyzer.clj:1222 cljs.analyzer/analyze
            analyzer.clj:1219 cljs.analyzer/analyze
             compiler.clj:873 cljs.compiler/compile-file*
             compiler.clj:984 cljs.compiler/compile-file
Caused by: java.lang.UnsupportedOperationException: nth not supported on this type: Symbol
                  RT.java:857 clojure.lang.RT.nthFrom
                  RT.java:807 clojure.lang.RT.nth
           ioc_macros.clj:418 cljs.core.async.impl.ioc-macros/eval5251[fn]
             MultiFn.java:227 clojure.lang.MultiFn.invoke
           ioc_macros.clj:627 cljs.core.async.impl.ioc-macros/eval5429[fn]
           ioc_macros.clj:110 cljs.core.async.impl.ioc-macros/all[fn]
            protocols.clj:143 clojure.core.protocols/fn
             protocols.clj:19 clojure.core.protocols/fn[fn]
             protocols.clj:31 clojure.core.protocols/seq-reduce
             protocols.clj:54 clojure.core.protocols/fn
             protocols.clj:13 clojure.core.protocols/fn[fn]
                core.clj:6177 clojure.core/reduce
           ioc_macros.clj:108 cljs.core.async.impl.ioc-macros/all[fn]
           ioc_macros.clj:674 cljs.core.async.impl.ioc-macros/parse-to-state-machine[fn]
            ioc_macros.clj:68 cljs.core.async.impl.ioc-macros/get-plan
           ioc_macros.clj:668 cljs.core.async.impl.ioc-macros/parse-to-state-machine
           ioc_macros.clj:809 cljs.core.async.impl.ioc-macros/state-machine
                macros.clj:18 cljs.core.async.macros/go
              RestFn.java:142 clojure.lang.RestFn.applyTo
                 core.clj:621 clojure.core/apply
            analyzer.clj:1129 cljs.analyzer/macroexpand-1
            analyzer.clj:1164 cljs.analyzer/analyze-seq
            analyzer.clj:1230 cljs.analyzer/analyze


 Comments   
Comment by Ghadi Shayban [ 18/Nov/13 11:07 PM ]

Tentative fix on branch ASYNC-37. Can someone review?





[ASYNC-41] Mult gets stuck when you put a value on the source chan and there are no taps on the first tick Created: 30/Nov/13  Updated: 12/Dec/13  Resolved: 12/Dec/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Radford Smith Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None
Environment:

ClojureScript


Attachments: Text File 0001-ASYNC-41-Make-mult-drop-values-when-there-are-no-tap.patch    
Patch: Code and Test

 Description   

If you have a mult and you put a value on its source channel, but there are no taps at the moment, the mult will get stuck and not put any values on future tap channels. Here's an example: http://cljsfiddle.net/fiddle/rads.mult-bug

In the example, no value will ever get put on the `tap1` chan. There are two possible solutions to this: a) drop all values going to the mult until a tap is created, or b) queue the values until a tap is created. I believe the first option is more straightforward, since if you have 1 tapped channel already and you go to 2 taps, the mult does not put old values on the new tap. This would make the behavior consistent going from 0 taps to 1 tap as well.



 Comments   
Comment by Radford Smith [ 30/Nov/13 10:45 PM ]

It looks like dropping values is already the default behavior on the JVM. In fact, this is the only difference in implementation for `mult` between the JVM and CLJS. I created a pull request with the fix and a regression test: https://github.com/clojure/core.async/pull/38

Comment by Leon Grapenthin [ 02/Dec/13 2:21 PM ]

This is similar to http://dev.clojure.org/jira/browse/ASYNC-26 of the CLJ version and has been fixed. Apparently the fix has not yet been ported to the CLJS version?

Comment by Radford Smith [ 02/Dec/13 4:24 PM ]

I attached the patch that was originally in the pull request.

Comment by David Nolen [ 09/Dec/13 12:16 PM ]

Thanks for the patch. Radford have you submitted your CA, it's required in order for us to merge patches in. Thanks!

Comment by Ghadi Shayban [ 09/Dec/13 12:32 PM ]

Sorry I missed this discussion. I copy ported 3f98 to master, Rich's original fix from the CLJ side of the project.

Comment by Timothy Baldridge [ 12/Dec/13 10:34 PM ]

Fixed by Ghadi





[ASYNC-45] Creating a timeout channel with a double causes the timeout-daemon to die Created: 09/Dec/13  Updated: 13/Dec/13  Resolved: 12/Dec/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Ben Poweski Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None


 Description   

I inadvertently passed a double to a timeout channel and discovered the following behavior using 0.1.242.0-44b1e3-alpha.

<code>
user=> (require '[clojure.core.async :as a])
nil
user=> (a/timeout 100.0)
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@1009d11d>
user=> Exception in thread "clojure.core.async.timers/timeout-daemon" java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Long
at java.lang.Long.compareTo(Long.java:50)
at java.util.concurrent.ConcurrentSkipListMap.doRemove(ConcurrentSkipListMap.java:1064)
at java.util.concurrent.ConcurrentSkipListMap.remove(ConcurrentSkipListMap.java:1896)
at clojure.core.async.impl.timers$timeout_worker.invoke(timers.clj:61)
at clojure.lang.AFn.run(AFn.java:24)
at java.lang.Thread.run(Thread.java:722)

user=> (.isAlive clojure.core.async.impl.timers/timeout-daemon)
false
<code>



 Comments   
Comment by Timothy Baldridge [ 12/Dec/13 10:32 PM ]

Fixed in master, added `:pre [(integer? msec)]` to timeout.

Comment by Rich Hickey [ 13/Dec/13 7:24 AM ]

I'd prefer we type hint ^long vs use a precondition





[ASYNC-36] Waiters should unblock on close! Created: 14/Nov/13  Updated: 29/Mar/14  Resolved: 22/Nov/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Herwig Hochleitner Assignee: Timothy Baldridge
Resolution: Declined Votes: 1
Labels: None


 Description   

Expected behavior

When a channel is closed, all readers and writers waiting for it, whether on a thread with the !! family of functions or in a go block, should unblock and return nil, as if the channel had been closed in the first place. This is expected since channels are frequently discarded after being closed.

Problem description

The operator >!! (used as example here) immediately returns, when used on a closed channel, however, if >!! is already waiting for a channel, which is then closed, >!! doesn't unblock. , stalling the thread indefinitely.
EDIT: The thread/go block can still be unblocked, by taking from the channel, however since close! signifies the end of the lifetime of a channel, subsequent takes on it cannot be considered idiomatic.

Example REPL Sessions

In this example, the future blocks indefinitely, even though the target channel is closed

This is a problem, since the >!! might be called in a try..catch holding resources and such.

The example also shows, that values can be read from a closed channel (and trigger processing), which might be ok for channel buffers, not so much for pending >!! that have side effects in their continuation.

> (def ch (async/chan))
> (future (>!! ch :cool)
          (println "done"))
> (<!! ch)
"done"
:cool
> (future (>!! ch :cool)
          (println "done"))
> (close! ch)
;; FIXME "done" should be printed here
> (<!! ch)
"done" ;; EDIT pending >!! can be taken from, same as with >!
nil
> (future (>!! ch :cool)
          (println "done"))
;; Same as here
"done"

EDIT Removed example documenting different behavior of threads and go blocks, since subsequent tests turned them out to behave the same.

References

This was first posted to github https://github.com/clojure/core.async/issues/36
Some discussion already happenend there.

http://dev.clojure.org/jira/browse/ASYNC-31 seems related with regard to the close! semantics of a write.



 Comments   
Comment by Leon Grapenthin [ 14/Nov/13 12:52 PM ]

If I try to reproduce your second future, after (<!! ch) "done" is printed correctly. I tried it twice today with "0.1.242.0-44b1e3-alpha".
Probably you didn't see "done" because it was printed in the nrepl-server buffer?

This would be the only proof of infinite blocking. Aside from that this report raises the question whether parked puts should be cancelled when a channel is closed. It would be great if the docstring of close! would state this more clearly (currently it says "Data in the channel remains available" which could also refer to the channels buffer).

Comment by Leon Grapenthin [ 15/Nov/13 11:43 AM ]

I could also not reproduce the second future hanging after the take with "0.1.256.0-1bf8cf-alpha"

Comment by Herwig Hochleitner [ 16/Nov/13 9:22 PM ]

You are right, I couldn't reproduce the infinite stall (and hope I never will).

I would indeed argue that parked gets and puts should be cancelled when a channel is closed. Otherwise the answer to the question "when can I read/write a channel and when should I do it?" gets very non-deterministic. Don't forget, channels are not only about data transmission but also about coordination, (i.e. thread scheduling, thus resource management).

e.g. the current behavior yields the rule: "only write if somebody's listening or if the channel is not going to be closed anytime soon otherwise you might stall forever". Is this intentional? Better than the alternatives?

Comment by Leon Grapenthin [ 17/Nov/13 10:55 AM ]

If you are taking from a channel, you can determine that it's closed by taking nil from it. If you are putting on a channel you can't determine whether it's closed, however the operation will immediately return if the channel is closed and not block.

However in all cases I used async in so far it seemed only natural to handle the closing of a channel on the same site where the puts are made and the channel was created.

Comment by Herwig Hochleitner [ 17/Nov/13 6:52 PM ]

Yes, but normally you wouldn't take/put/do anything to a channel after calling close! on it.
That's what I meant when I said it wouldn't be idiomatic to require taking from a channel after a close! just to make sure that no writers are blocked.

Comment by Leon Grapenthin [ 18/Nov/13 3:16 PM ]

I would just say that there is no reason to close a channel at all when puts are still pending. You close! the channel only when you are done putting with the reason to communicate to the taking site that nothing more is going to come through the channel.

I find it hard to see the benefit of unblocking parked puts! with close!. They could be in a loop and they don't know that they were unblocked by a close!. If the putting site could determine that the target channel has been closed (by an exception thrown from put! that is unimplemented), it could stop putting permanently - But then it would know what ended up on the channel (and can be taken) and what did not end up on the channel (and can not be taken). Both information would be lost on the putting site if parked puts can be cancelled by a close without notification. You are right that they would be unblocked, but they would probably run infinite loops or simply do more useless puts.

As I see it: Until the put! exception (from the put! docstring) has been implemented one has to avoid putting onto closed channels. If it ever will be implemented it adds another way to determine whether a channel was closed (without taking from it) which I would prefer over cancellation via close!.

EDIT: I forgot to add that you can of course invoke @(.closed ch) to determine whether a channel has been closed but it is questionable whether this is officially supported or an implementation detail that may change.

Comment by Herwig Hochleitner [ 19/Nov/13 2:55 PM ]

> I would just say that there is no reason to close a channel at all when puts are still pending

Channels are designed to be multi-writer and multi-reader, so often you will want to close! a channel from outside. e.g. when the user clicks cancel.
As far as I understand it, close! is the intended interface for such things.

> They could be in a loop and they don't know that they were unblocked by a close!.

Well, that's actually the same when the channel is closed beforehand. And yes, failed puts should be distinguishable from regular puts, but that's ASYNC-31
Should also throw if a pending put gets unblocked by close.

Comment by Leon Grapenthin [ 19/Nov/13 7:15 PM ]

I think I understand your point now. Basically your idea is that channels should be close-able from everywhere, anytime, independently of any puts or takes. However the more I think about it, I can not prefer it over the current implementation:

Being able to close channels from everywhere seems like something that would make it easier to deal with channels and associated processes on the first look. But it would always require a special implementation on the putting sites: Whenever you put on a channel, you'd have to check whether it has been closed and you'd have to implement further decision making based on that information.

The current implementation leads one to do closing in sync with puts: If the user clicks cancel, this is the information the code should process as "Stop putting, Close channel" in that order. If the channel was closed first, that would first produce a new (less valuable) information which would need to be processed (with less information about what happened) which in my view would make things only more complicated.

The user having clicked cancel is specific and valuable information about something that has happened in the past and thus can not be realized in zero time or instantly anyway. Users have to wait as well. The user request can be taken from one channel of user-events. Putting onto the an output channel can properly come to an end first and then the output channel can be closed. Display or other further processing of the last produced output value will happen and the put site can rely on it. With the current constraints one writes code where this information of the user having clicked cancel is directed to the site affected by it, the site were the output values are produced, what is what the user desires to come to an end soon.

This enforcement of handling closing on the calling site is in my view the win for the current implementation: Channels are really like cables were the possibility of them being cut suddenly is not a desired feature but something one would rather avoid.

Comment by Herwig Hochleitner [ 19/Nov/13 10:55 PM ]

> Basically your idea is that channels should be close-able from everywhere, anytime, independently of any puts or takes.

In fact, they are! It's just that the semantics don't seem well-defined to me.

> This enforcement of handling closing on the calling site is in my view the win for the current implementation

There is no such enforcement. Just out of interest: How would you design such enforcement, from an API / Semantics POV? How would you disallow arbitrary closes?

> Channels are really like cables were the possibility of them being cut suddenly is not a desired feature but something one would rather avoid.

We should design not only for desired cases, but also for failure modes. "would rather avoid" isn't sufficient when thinking about the possible combinations of an API.

Also in the real world, cables do get unplugged, without either side getting stuck permanently and plugs/sockets very much are desired features in cable-related technology.

Please do me a favor, play advocatus diaboli and try to argue for a second that channels should be closeable from outside of the writer context.
A good starting point: The writer might already be blocking for an unforseen amount of time when the time to close it has come.

Comment by Leon Grapenthin [ 20/Nov/13 5:25 PM ]

I know that there is no real enforcement of handling closing on the putting site. But it's what you are lead to do when you want to avoid unnecessary puts.

If you call your suggestion (closing from anywhere) a failure - it's a failure that can be avoided by simply not doing it.

I tried to imagine cases where channels should be close-able from outside the writer context yesterday a lot before I posted. I simply can't find any. What you are suggesting as a starting point to find such a case is a scenario where you want to cancel a put operation that has already begun. For that scenario we have alts! where you have one put operation that can take a long time and another channel to communicate the cancellation through. If the cancellation comes first, the put operation will not happen even though it was blocking.

Here is a link to an extended example where I have implemented such a scenario: https://www.refheap.com/21103

Comment by Herwig Hochleitner [ 21/Nov/13 10:14 AM ]

I'm tempted to respond with a sole [closed from the reader side] to demonstrate a case where it's valid to close from outside of the writer context, but of course that would be rude. Instead let me try to get an exact grasp on our differing views:

I think, the full API of a library should be usable or produce visible errors immediately. In my view there is no such thing as "avoid by simply not doing it" in API design (except for bad Java APIs
You are certainly free to view a certain legal combination of API calls as failure but I wouldn't be so quick. I think the API of core.async offers close! as a standalone operation for a reason. I think the reason is, that channels are designed for broader applicability than just "dump into channel, then close".

I'd still like to hear a proposal on how to effectively prevent closing from outside of the writer (my guess is: there is no feasible way with the current API).
The reason I insist on this:
There are 2 things, programmers don't like: deadlocks and "don't do that". The combination of those two are what's broken with lock concurrency. Please let's not regress to that "state of the art".

OK here is an example, please don't discard it due to the fact that writers currently can't distinguish between an open channel and a closed one, that's for ASYNC-31:
Take a channel akin to range: producing an infinite number of values. You generate it somewhere in your program, pass it around and then consume it somewhere else.
How should this work?
1) Requiring me to design my program such I have the close condition available at the channel creation site, even though the producer might be completely generic, while only the consumer logically knows about the proper closing time, OR
2) Just let me close the channel from the consumer, when it doesn't want to consume anymore?

Your alts! example is also an excellent point in my case: Even though the put operation will never happen, it's still remaining in a pending state, tying up resources.

Comment by Leon Grapenthin [ 21/Nov/13 8:37 PM ]

Let me get right back to your last point: I have added a little benchmark of the blocking put operation to my example to prove that the put operation is not in pending state and unblocks as soon as :stop is dispatched.

Unfortunately I don't quite get what you mean by a "sole". "Closing from the reader side" is not necessary with the current API.

Now regarding your example:
1) In this point it is not quite clear to me whether you mean to distinguish between "creation site" and putting site. I will assume that you mean both and the same thing and call it production site. My answer would be: Yes. Design your api/program so that you have a close-condition available, even though the producer might be completely generic. One example for such a close-condition is in the example I have linked to: Taking :stop from a seperate channel stops production and closes the channel. The consumer can determine the proper closing time and send :stop, as demonstrated in my example.
2) I know that this is what you want, but you would still need the close condition at the production site to stop putting. Unless you have determined that the channel has been closed, you'd put the next value onto the chan. With the current implementation, such a scenario would heat up the CPU. If you could determine closing on the production site for example by an exception, you would do exactly the same thing as in point 1), but with less information, as I have pointed out in earlier comments.

I believe programmers like "don't do that" much more than "you can't do that". So I think it's fine that you can close! from everywhere. I had some cases myself where very few unnecessary put operations where tolerable as I knew that they would not be possible again after a very short predictable amount of time (In fact when the user clicked cancel: I knew that the interface would be removed from the screen immediately and that a few puts triggered by event listeners wouldn't mind the CPU). So I wouldn't even go so far as to prevent closing. But what I'd really like is that when I develop an API for a library built on top of core.async is this: I don't want to expect channels being closed every time I do a put. I don't want to write an exception-catcher every time. But if what you have proposed would be reality, that would be an unavoidable necessity. Otherwise, I'd never be sure whether values I have put were received, or the channel has been closed. What if I write a function that takes values from one channel and puts them onto another (like core.async/pipe), and suddenly the output-channel was closed? Would I have to close the input channel then as well? Ownership would be totally undefined in such a scenario and lead to all kinds of confusion and most likely lots of boiler-plate code. If I wrote anything that does an unpredictable amount of puts, I'd provide one or multiple facilities to stop the puts.

You may also want to have a look at the C# implementation of the cancellation of tasks: Cancellation tokens are used to determine cancellation on the production site at a specific point in execution order and are passed as an additional parameter: "If library code provides cancellable operations, it should also provide public methods that accept an external cancellation token so that user code can request cancellation." (http://msdn.microsoft.com/en-us/library/vstudio/dd997364.aspx).

Or erlang, where a "finished" message is passed from the production site: http://www.erlang.org/doc/getting_started/conc_prog.html#id67009

Or in go: "A sender can close a channel to indicate that no more values will be sent." and "Note: Only the sender should close a channel, never the receiver." (http://tour.golang.org/#66)

And then there is Haskell, where you can't close channels, but only kill threads...

Comment by Timothy Baldridge [ 22/Nov/13 2:47 PM ]

Copy of my comments to the email in clojure-dev:

Example repl session:

user=> (def c (chan))
#'user/c
user=> (go (>! c 42) (println "done"))
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@29794f5b>
user=> (go (>! c 42) (println "done"))
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@7848089e>
user=> (go (>! c 42) (println "done"))
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@1b6b43ac>
user=> (go (>! c 42) (println "done"))
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@464f0728>
user=> (close! c)
nil
user=> (<!! c)
done
42
user=> (<!! c)
42done

user=> (<!! c)
done
42
user=> (<!! c)
done
42
user=> (<!! c)
nil
user=>

The library works as expected. If you want the pending puts to be dropped, feel free to write something like this:

(defn close-and-flush [c]
(close! c)
(clojure.core.async/reduce (fn [_ _] nil) [] c))

Semantics are now:

user=> (def c (chan))
#'user/c
user=> (go (>! c 42) (println "done"))
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@284b38f9>
user=> (go (>! c 42) (println "done"))
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@43bbaad3>
user=> (go (>! c 42) (println "done"))
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@16cc601f>
user=> (go (>! c 42) (println "done"))
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@630f83c9>
user=> (close-and-flush c)
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@3f1d023f>done
done

done
done
user=>

--------

The semantics are not going to change. Pending puts are flushed. Pending takes are given nil after a closed channel flushes. This is the way the library was designed to operate. By default the library will not discard data unless you configure it to do so, to have pending puts automatically throw away values on a channel would cause many errors, and make libraries harder to reason about.

Leon is right, close! basically means "after all pending values have been written, close the channel".

Comment by Alexander Kauer [ 29/Mar/14 4:36 AM ]

Hi,

since I ran into the same problem (see report ASYNC-60 , somehow I overlooked this report first) I think the documentation should explicitly state that behaviour to avoid further confusion for others.





[ASYNC-35] Using onto-chan with nonending sequence causes non-gc-able, infinitely-looping go block Created: 12/Nov/13  Updated: 20/Apr/14  Resolved: 20/Apr/14

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Brian Lubeski Assignee: Rich Hickey
Resolution: Completed Votes: 0
Labels: None
Environment:

org.clojure/core.async 0.1.256.0-1bf8cf-alpha



 Description   
(close! (to-chan (range)))

The above code causes my CPU to run at around 95% until I kill the process. (NOTE: This eventually leads to an OutOfMemoryError – see ASYNC-32).

Here is what I think is happening: after closing the channel returned by to-chan, all subsequent puts to that channel by the to-chan go block succeed immediately without blocking. Because the to-chan go block never blocks on its drain channel, it runs continuously and can't be GC'd (if I understand things correctly).



 Comments   
Comment by Leon Grapenthin [ 15/Nov/13 10:16 AM ]

I'd expect the behavior. Neither can to-chan know that (range) returns an infinite sequence, nor can it know that it's output channel has been closed.

Comment by Brian Lubeski [ 11/Feb/14 11:27 AM ]

Resolved in 0.1.278.0-76b25b-alpha.





[ASYNC-85] Add transducer support for ClojureScript Created: 13/Aug/14  Updated: 13/Aug/14  Resolved: 13/Aug/14

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Major
Reporter: Luke VanderHart Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: File cljs-transducers.diff    
Approval: Ok

 Description   

The attached patch adds transducer support, to keep ClojureScript APIs in sync with Clojure's (as far as possible).

Tests pass and the code is correct as far as I can discern but review is appreciated.



 Comments   
Comment by Luke VanderHart [ 13/Aug/14 12:58 PM ]

I pushed this patch directly after getting push access from Rich & Stu.





[ASYNC-93] can't use fn inside go macro Created: 05/Oct/14  Updated: 16/Oct/14  Resolved: 15/Oct/14

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Alexei Guevara Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None
Environment:

osx 10.9.2 / java 1.7.0_51-b13 / clojure 1.6



 Description   

Can't compile this expression

(ns example
  (:require [clojure.core.async :refer [chan go >! put!]]))

(let [ch (chan)]
  (go (fn [] (>! ch 1))))

I'm getting this error

clojure.lang.Compiler$CompilerException: java.lang.IllegalArgumentException: No method in multimethod '-item-to-ssa' for dispatch value: :fn, compiling:(.../example.clj:5:1)

Whereas this expression compiles with no issues

(let [ch (chan)]
  (go (fn [] (put! ch 1))))

I reduced the original code where I found the issue to the first expression.



 Comments   
Comment by Kevin Downey [ 14/Oct/14 3:37 PM ]

the go macro does not descend in to and transform functions. >! only works inside the go macro, so regardless, the first example is bad code, so it should throw some kind of error. I am not sure that error shown is the correct error it should throw, or why the second example doesn't throw. the ticket doesn't mention what version of core.async is being used

Comment by Alexei Guevara [ 14/Oct/14 3:41 PM ]

I was using core.async v0.1.346.0-17112a-alpha.

Comment by Nicola Mometto [ 14/Oct/14 5:37 PM ]

The second example doesn't throw because `go` will only transform forms that are, or contain in their sub-forms, channel operations for go blocks (>!, <!, alts!), put! is not one of those so the go macro won't transform the expression.

Comment by Ghadi Shayban [ 15/Oct/14 10:43 PM ]

Kevin and Nicola are correct, the go macro stops transformation at function boundaries, and and only transform alts! >! and <!

Comment by Alexei Guevara [ 15/Oct/14 11:11 PM ]

Not transforming function definitions inside the go macro makes perfect sense. But, it will also make sense to fail with a message more meaningful than "No method in multimethod '-item-to-ssa' for dispatch value".

Comment by Ghadi Shayban [ 15/Oct/14 11:20 PM ]

Agreed, created ASYNC-98.





[ASYNC-115] Node.js target should support :main Created: 10/Feb/15  Updated: 10/Feb/15  Resolved: 10/Feb/15

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Comments   
Comment by David Nolen [ 10/Feb/15 12:46 PM ]

wrong place.





[ASYNC-13] go blocks don't handle explicitly namespaced calls to <! and >! Created: 22/Jul/13  Updated: 26/Jul/13  Resolved: 26/Jul/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Edward Cho Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None
Environment:

[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-1844"]
[org.clojure/core.async "0.1.0-SNAPSHOT"]



 Description   

When <Unable to render embedded object: File (, >) not found., or the go macro is explicitly namespaced, the assertion that <! or >! was called outside of a go block is raised.

Example:
(ns foo
(:require [cljs.core.async :as async)
(:require-macros [cljs.core.async.macros :refer [go]))

;; raises assertion error
(let [c (async/chan)]
(async/go
(loop []
(async/<! c)
(recur))))



 Comments   
Comment by Timothy Baldridge [ 26/Jul/13 9:34 AM ]

Fixed in master https://github.com/clojure/core.async/commit/12af7d8dc207a42f388936318dd2eeb48d1b03c8

Was a problem only in CLJS





[ASYNC-22] IOC macro does not handle Dot special form Created: 09/Sep/13  Updated: 04/Oct/13  Resolved: 04/Oct/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Ben Mabey Assignee: Timothy Baldridge
Resolution: Completed Votes: 0
Labels: None
Environment:

I've tested with using the latest snapshot of core.async and latest on github.



 Description   

This code:

(go (. clojure.lang.Numbers (add 1 2)))

Results in this error:

CompilerException java.lang.RuntimeException: Unable to resolve symbol: add in this context, ...

Looking at the expansion of the state machine the problem seems to be that SSA transformation is treating the (add 1 2) as a separate expression that needs to be evaluated (and assigned) before the clojure.lang.Numbers:

...
(clojure.core/let [inst_4648 (add 1 2)
                   inst_4649 (. clojure.lang.Numbers inst_4648)
                   state_4651 state_4651]
...

The newer / form works fine, e.g. (Math/abs -2), and that is how I would write static method calls myself but I am using macros that expand to the older dot syntax above.

Do you see this as a case the IOC macro should be handling?



 Comments   
Comment by Timothy Baldridge [ 04/Oct/13 1:42 PM ]

Fixed in master





[ASYNC-12] Add chan? or channel? function to identify a channel Created: 19/Jul/13  Updated: 24/Mar/15  Resolved: 12/Dec/13

Status: Resolved
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Brenton Ashworth Assignee: Timothy Baldridge
Resolution: Declined Votes: 0
Labels: None


 Description   

There are cases where one may be handed a value which could possibly be a channel. It would be nice to have a function which returns true if a value is a channel. This can currently be done from user code but requires reaching into the clojure.core.async.impl.channels namespace and depending on an implementation detail.

(defn channel? [c]
(satisfies? channels/MMC c))



 Comments   
Comment by Hugo Duncan [ 26/Sep/13 9:20 AM ]

I ran into the need for this when writing a schema to validate input arguments.

Comment by Timothy Baldridge [ 12/Dec/13 10:37 PM ]

We're rejecting this feature for now. If you need to check if an object implements the correct interfaces, feel free to dive into clojure.core.async.impl.protocols and check for satisfies? against ReadPort and WritePort. Not only do these allow you to accept ReadPorts that aren't channels, but it also keeps the main interface from getting cluttered.

At least this was the argument Rich proposed last time we talked. If this won't work, feel free to submit a new ticket or start a clojure-dev mailing list thread.

Comment by Kaspars Dancis [ 24/Mar/15 3:42 PM ]

Would it make sense to move or at least alias the protocols in clojure.core.async? .impl. seem to imply that it's not public interface and is subject to change.





[ASYNC-42] (CLJS) (try (catch :default)) inside a cljs go block raises an exception Created: 07/Dec/13  Updated: 13/Feb/17

Status: Reopened
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Travis Vachon Assignee: Unassigned
Resolution: Unresolved Votes: 2
Labels: try-catch

Attachments: Text File async_42.patch     Text File async_42.v2.patch     Text File try-catch-default.patch    

 Description