<< Back to previous view

[ASYNC-92] go macro removes binding forms that are intialized with logical false value Created: 03/Oct/14  Updated: 17/Oct/14

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

Type: Defect Priority: Major
Reporter: Oleh Palianytsia Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None
Environment:

org.clojure/core.async "0.1.346.0-17112a-alpha"



 Description   
(require '[clojure.core.async :as a])

(a/go (let [a nil] (a/alts! (if a <whatever> <whatever>)))) // Unable to resolve a
(a/go (let [a nil] (a/<! (if a <whatever> <whatever>))) // Unable to resolve a

Seems that 'go' macro removes falsely initialized symbols that are used as channels, because
in both cases there's exception, that says " Unable to resolve symbol: a in this context".



 Comments   
Comment by Willy Blandin [ 17/Oct/14 12:19 PM ]

Confirmed.
Bug was introduced between 0.1.278.0-76b25b-alpha and 0.1.295.0-9ea6ef-alpha.

Comment by Willy Blandin [ 17/Oct/14 12:27 PM ]

Worked around with:

(defmacro workaround-async-92
  "Hack to workaround core.async bug
   cf. http://dev.clojure.org/jira/browse/ASYNC-92"
  []
  ;; has to be a list
  `(do nil))

(let [a (workaround-async-92)]
  ...)




[ASYNC-64] Race condition when closing mults Created: 29/Apr/14  Updated: 16/Oct/14

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

Type: Defect Priority: Major
Reporter: James Reeves Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: mult

Approval: Triaged

 Description   

When a mult is tapped at around the same time as the source channel is closed, the tapped channel may not be closed.

(require '[clojure.core.async :refer (chan mult tap close!)])
(let [s (chan)
      m (mult s)
      c (chan)]
  (tap m c)
  (close! s)
  (impl/closed? c))

The above code will sometimes return true, and sometimes return false.

Cause: This is caused by the following code in the mult function:

(if (nil? val)
  (doseq [[c close?] @cs]
    (when close? (close! c)))

Any channels tapped after cs is dereferenced will not be closed.

Approach: A possible solution to this could be to always close channels tapped to a closed source. i.e.

(let [s (chan)
      m (mult s)
      c (chan)]
  (close! s)
  (tap m c))  ;; will always close c

This could be achieved by adding a flag to the cs atom to denote whether the mult is open or closed. If it's closed, any tapped channel is closed automatically.



 Comments   
Comment by James Reeves [ 30/Apr/14 6:05 AM ]

For reference, below is the custom fix for mult I'm using:

(defn mult [ch]
  (let [state (atom [true {}])
        m (reify
            Mux
            (muxch* [_] ch)
            Mult
            (tap* [_ ch close?]
              (let [add-ch    (fn [[o? cs]] [o? (if o? (assoc cs ch close?) cs)])
                    [open? _] (swap! state add-ch)]
                (when-not open? (close! ch))
                nil))
            (untap* [_ ch]
              (swap! state (fn [[open? cs]] [open? (dissoc cs ch)]))
              nil)
            (untap-all* [_]
              (swap! state (fn [[open? _]] [open? {}]))))
        dchan (chan 1)
        dctr (atom nil)
        done (fn [_] (when (zero? (swap! dctr dec))
                       (put! dchan true)))]
    (go-loop []
      (let [val (<! ch)]
        (if (nil? val)
          (let [[_ cs] (swap! state (fn [[_ cs]] [false cs]))]
            (doseq [[c close?] cs]
              (when close? (close! c))))
          (let [chs (keys (second @state))]
            (reset! dctr (count chs))
            (doseq [c chs]
              (when-not (put! c val done)
                (swap! dctr dec)
                (untap* m c)))
            (when (seq chs)
              (<! dchan))
            (recur)))))
    m))
Comment by David Nolen [ 14/Oct/14 6:10 AM ]

Is this also fixed in master? Thanks.

Comment by Ghadi Shayban [ 15/Oct/14 11:09 PM ]

I understand the scenario, but honestly I'm not sure this is a bug in mult or the usage. A channel shouldn't be expected to always yield a take. The consumer of the "late tap" can guard against it with alts or some other mechanism, and also you can enforce a no-late-taps through a policy on the "production" side of things.

Rich Hickey can you weigh in?

Comment by James Reeves [ 16/Oct/14 3:51 AM ]

The "tap" function currently has an explicit "close?" flag, and if a tapped channel isn't guaranteed to close when the source channel closes, that argument probably shouldn't exist. Also, if auto-closing taps is taken out, should we remove the "close?" argument on "sub" as well?

Comment by Ghadi Shayban [ 16/Oct/14 11:34 AM ]

It's more than respecting the flag. Related to the close behavior, channels can tap and untap without receiving anything while the mult process happily distributes a value to another set of channels (like the ABA problem). Could also make it an error to tap after the close is distributed to the last deref'ed set of channels. That is different than the familiar permanent nil receive, but mults already differ from simple channels.





[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-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-97] CLJS: alts! sporadically failing to unblock despite channel activity (Safari 7) Created: 15/Oct/14  Updated: 16/Oct/14

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

Type: Defect Priority: Major
Reporter: Oliver Charles Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File gistfile1.txt     File main.cljs     File socket.cljs    

 Description   

Hi all, bit of a tricky bug to report here... We're seeing some problems with using core.async in ClojureScript on Safari 7. Our application is built around a large event loop that blocks on a message from one of many channels that correspond to user activity or API calls. The problem seems to lie within this event loop - we are using alts! to pull a message out of any available channel, but sometimes logging shows that we reach alts! and never unblock. However, with a little more logging, I can see that there are subsequent writes to one of the channels in the list of channels passed to alts!, so I'm not really sure what's going on.

That's the high level overview, now on to some code.

Our main event loop is as follows:

(log "Entering main event loop.")
  (go
    (while true
      (log "alts! channel hashes: " (map hash (:channels @app)))
      (let [[message channel] (alts! (seq (:channels @app)))]
        (log "alts! unblocked, calling our process-message")
        (swap! app process-message message channel)
        (log "process-message completed, looping"))))

process-message here is our a function internal to our application, but I don't think it's details are necessarily important. In the scenario where Safari gets stuck, the log looks like:

[Log] process-message completed, looping (main.js, line 62)
[Log] alts! channel hashes:  (16 12 19 33) (main.js, line 82)
[Log] Socket connected. (socket.js, line 309)
[Log] put! to channel with hash  19 (socket.js, line 86)
[Log] The message is [:metronome [:staff [{:description nil, :deletable true, :email nil, :isAdmin true, :isTrainer false, :telephone nil, :name "Fynder Admin", :picture nil, :userId 1} {:description nil, :deletable fa... (socket.js, line 87)
[Log] put! callback gave us true (socket.js, line 89)
[Debug] Metronome: staff data decoded. put! complete.: 12.282ms (socket.js, line 93)
[Log] put! to channel with hash  19 (socket.js, line 86)
[Log] The message is [:metronome [:class-types [{:deletable false, :picture nil, :name "CycleCore", :id 2, :description "CycleCore is a 55-minute dual workout concept that combines 30 minutes of intense cardiovascular ... (socket.js, line 87)
[Log] put! callback gave us true (socket.js, line 89)
[Debug] Metronome: class-types data decoded. put! complete.: 1.288ms (socket.js, line 93)
[Log] put! to channel with hash  19 (socket.js, line 86)
[Log] The message is [:metronome [:locations [{:studios [{:deletable false, :name "Kensington", :id 1, :locationId 1, :description "Studio (11a) sits just off Stratford Road in Stratford Studios. To find us, just pass ... (socket.js, line 87)
[Debug] Metronome: locations data decoded. put! complete.: 0.884ms (socket.js, line 93)

Note that we see a log entry for "alts! channel hashes", but we never seen "alts! unblocked". However, note the list of hashes passed to alts!. Channel 19 is mentioned, but subsequently we put! to channel 19... yet we still don't get unblocked. Something that also strikes me as suspicious, is that while we're blocked at alts!, two calls to put! have succeeded immediately, for a channel that is bounded to contain only one element at a time. Maybe I'm misunderstanding something, but I wouldn't expect the immediate-put callback to be invoked more than once. Interestingly that last put! doesn't invoke the callback.

Unfortunately, reproduction of this bug is reasonably difficult. I can somewhat reliably reproduce it by quitting Safari, re-opening it, and navigating to the dev server. About 1 in 15 attempts get stuck in this fashion. I wondered if it was something to do with Safari's MessageChannel implementation - you can see in the log entries where nexttick.js calls its callback, which seems to be how dispatch is working in my browser.

I'd be very happy to help provide any more information that's useful, but this problem is now outside my ability to debug it. While the code is proprietary, I'd be happy to temporarily add people to the Github project in order to try and get this fixed. We have development APIs servers that you can point at, so it should be just a case of running lein cljs.

I've attached our code for our Socket.io wrapper and our main event loop. Sadly I do not yet have a minimal test-case - I wouldn't really know where to begin.



 Comments   
Comment by Oliver Charles [ 15/Oct/14 7:37 AM ]

I went deep into the guts of the Google Closure library and changed getSetImmediateEmulator_ to:

goog.async.nextTick.getSetImmediateEmulator_ = function() {
  // Fall back to setTimeout with 0. In browsers this creates a delay of 5ms
  // or more.
  return function(cb) {
    goog.global.setTimeout(cb, 0);
  };
};

and I haven't been able to get it stuck. So maybe MessageChannel has problems in Safari...

Comment by Ghadi Shayban [ 15/Oct/14 10:40 PM ]

Hi Oliver, seems like a race, and we'll figure this out.

Would you mind compare running upon 0.1.319.0-6b1aca-alpha vs 0.1.346.0-17112a-alpha ?

alts! should be passed an indexed collection/vector btw. Passing a seq wouldn't cause this bug, just something to note.

Comment by Oliver Charles [ 16/Oct/14 6:53 AM ]

Hi Ghadi,

0.1.319.0-6b1aca-alpha is what the initial report was against - I should have mentioned that. So 0.1.319.0-6b1aca-alpha does get stuck.

0.1.346.0-17112a-alpha however does not get stuck, which is odd - as I'm sure I tried upgrading to this! I've tried on two Macs that are normally problematic, and they didn't get stuck once. I'm pushing this out to more of our testers and will see what happens.

Comment by Oliver Charles [ 16/Oct/14 7:16 AM ]

Aha, I knew it wouldn't be that easy! Upon releasing this to production, it immediately froze again. The dev server runs with very different optimisations though, so I'm going to build a production release and serve that locally - will see what happens there.

Comment by Oliver Charles [ 16/Oct/14 7:28 AM ]

Yep, definitely a problem with optimisations. Here is my Shadow Build configuration

(ns fynder.shadowbuild
  (:require [clojure.java.io :as io]
            [shadow.cljs.build :as cljs]))

(defn define-modules [state]
  (-> state
      (cljs/step-configure-module :cljs '[cljs.core clojure.walk clojure.string cljs.reader cljs.core.async] #{})
      (cljs/step-configure-module :test-support '[inflections.core no.en.core enfocus.bind fynder.winchan] #{:cljs})
      (cljs/step-configure-module :devel '[fynder.devel] #{:cljs})
      (cljs/step-configure-module :admin '[fynder-admin.main] #{:cljs})
      (cljs/step-configure-module :trainer '[fynder-trainer.main] #{:cljs})
      (cljs/step-configure-module :mobile '[fynder-mobile.main] #{:cljs})
      (cljs/step-configure-module :sweatybetty '[fynder-sweatybetty.main] #{:cljs})
      (cljs/step-configure-module :loader '[fynder-loader.loader] #{:cljs})))

(defn dev
  "build the project, wait for file changes, repeat"
  [& args]
  (let [state (-> (cljs/init-state)
                  (cljs/enable-source-maps)
                  (assoc :optimizations :advanced
                         :pretty-print false
                         :work-dir (io/file "target/cljs-work")
                         :public-dir (io/file "resources/dev")
                         :public-path "")
                  (cljs/step-find-resources-in-jars)
                  (cljs/step-find-resources "src/cljs/")
                  (cljs/step-finalize-config)
                  (cljs/step-compile-core)
                  (define-modules))]
    ;; compile, flush, reload, repeat
    (loop [state state]
      (let [new-state (try
                        (-> state
                            (cljs/step-compile-modules)
                            (cljs/flush-unoptimized)
                            (cljs/wait-and-reload!))
                        (catch Throwable t
                          (prn [:failed-to-compile t])
                          (.printStackTrace t)
                          (cljs/wait-and-reload! state)))]
        (recur new-state)))))

(defn prod
  "build the project, wait for file changes, repeat"
  [& args]
  (-> (cljs/init-state)
      (cljs/enable-emit-constants)
      (cljs/enable-source-maps)
      (assoc :optimizations :advanced
             :pretty-print false
             :work-dir (io/file "target/cljs-work")
             :public-dir (io/file "resources/prod")
             :externs ["react/externs/react.js"
                       "externs/base32.js"
                       "externs/jquery.js"
                       "externs/react_addons.js"
                       "externs/fastclick.js"
                       "externs/socket.io.js"
                       "externs/moment.js"
                       "externs/papa.js"
                       "externs/markdown.js"
                       "externs/xss.js"
                       "externs/facebook.js"
                       "externs/checkout.js"])
      (cljs/step-find-resources-in-jars)
      (cljs/step-find-resources "src/cljs/")
      (cljs/step-finalize-config)
      (cljs/step-compile-core)
      (define-modules)
      (cljs/step-compile-modules)
      (cljs/closure-optimize)
      (cljs/flush-to-disk)
      (cljs/flush-modules-to-disk)))

If I run in the dev profile, then I can't get it stuck. If I switch over to the production profile (and serve the result of lein publish with python's SimpleHTTPServer), then Safari does get stuck.





[ASYNC-90] Pub/sub leaks memory Created: 13/Sep/14  Updated: 15/Oct/14

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

Type: Defect Priority: Major
Reporter: Ziyang Hu Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

[org.clojure/clojure "1.6.0"]
[org.clojure/core.async "0.1.303.0-886421-alpha"]

java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode) (reproducible on OpenJDK 7 as well)

OS X 10.9.4 (reproducible on Ubuntu Linux 14.04 as well)



 Description   

The following code will cause OOME:

(require '[clojure.core.async :refer [chan close! <! pub sub unsub go timeout]])

(def p* (chan))

(def p (pub p* :topic))

(go
  (loop []
    (let [s (chan)
          t (rand-int Integer/MAX_VALUE)]
      (sub p t s)
      (<! (timeout 10))
      (unsub p t s)
      (close! s)
      (recur))))

(It grows slowly: to see the OOME in a reasonable amount of time, either give JVM very small
memory like 64m, or remove the timeout step.)

I tried to profile the code, and the reason seems to be that even though I
unsubed the channel from the port, something is still retained which causes
the heap to be used up.



 Comments   
Comment by Ziyang Hu [ 13/Sep/14 8:50 AM ]

Here is the problem:

https://github.com/clojure/core.async/blob/96de9a47ac511d9bb4309645a3bc594a2fc0c33a/src/main/clojure/clojure/core/async.clj#L826-L828

When unsub* is called, it just untaps the channel from the mult specified by the topic. The mult still remains in the atom called mults even if the mult has no taps left.

I can't think of a clean fix for this problem, since currently the channels which are tapping a mult aren't exposed, i.e., we currently have no way of knowing if a mult has any taps on it.

Comment by Ghadi Shayban [ 15/Oct/14 11:27 PM ]

I also cannot think of a clean fix, as mults do not expose their registrants. (The notion of "current" is a concurrent system is subtle)
Besides saying (and perhaps amending the docstring) that pubs are indeed resources, their footprint grows by the # of seen topics, and that resources should almost always be bounded.





[ASYNC-98] Less hostile message for #'go stopping at (fn [] ) boundaries Created: 15/Oct/14  Updated: 15/Oct/14

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

Type: Enhancement Priority: Minor
Reporter: Ghadi Shayban Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: errormsgs


 Description   

ASYNC-93 has an example of a not nice message when #'go attempts to shred through a (fn []) form. Maybe we can improve this, but then again creating a (fn []) in a block should be permitted, though the inner contents of it will not be transformed.






[ASYNC-51] Core.async memory leak in Safari and Mobile Safari Created: 21/Jan/14  Updated: 15/Oct/14

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

Type: Defect Priority: Major
Reporter: Bruce Hauman Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Mobile Safari on iOS 7.0; Safari 6.1 on OSX Lion



 Description   

Chaining together channels apparently leaks memory in Safari.

A statement such as

(def test [input-chan]
  (map< identity (map< identity (map< identity input-chan))))

will leak memory when the channels are used. The longer the chain the more memory.

I have created an example repository and an example page.

The repo and the example code is here:
https://github.com/bhauman/checkmemleak/blob/master/src/checking_safari_leak/core.cljs

The demonstration page is here:
This link will leak
http://rigsomelight.com/checkmemleak/?leak=true
This link will not
http://rigsomelight.com/checkmemleak

The leak is pretty darn severe.



 Comments   
Comment by Bruce Hauman [ 21/Jan/14 4:55 PM ]

I have just confirmed this is also a problem in Safari Version 7.0.1 (9537.73.11) on Mavericks.

Comment by Bruce Hauman [ 23/Jan/14 7:13 PM ]

I updated the example page.

http://rigsomelight.com/checkmemleak/index.html

This link wont leak:
http://rigsomelight.com/checkmemleak/index.html#comp-partial

This link will leak:
http://rigsomelight.com/checkmemleak/index.html#map<

There is navigation to try the different implementations and optimization modes.

To be clear map<-chain, custom-map, map<, and map> all exhibit the leak in :none and simple optimization modes.

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

To make sure this ticket has all the necessary information - if I remember correctly even advanced optimization is affected? Am I correct Bruce?

Comment by Bruce Hauman [ 15/Oct/14 12:53 PM ]

Yes, it affected advanced optimization. I haven't checked if this is still an issue.





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

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

Type: Enhancement Priority: Major
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None

Attachments: Text File 0001-update-to-tools.analyzer.jvm-0.5.6.patch     Text File 0001-update-to-tools.analyzer.jvm-0.6.1.patch    
Patch: Code
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.





[ASYNC-42] (try (catch :default)) inside a cljs go block raises an exception Created: 07/Dec/13  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: Travis Vachon Assignee: Unassigned
Resolution: Completed Votes: 2
Labels: cljs

Attachments: Text File async_42.patch     Text File async_42.v2.patch     Text File try-catch-default.patch    

 Description   

test demonstrating issue and patch fixing it here: https://github.com/clojure/core.async/pull/39



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

code + test

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

add {{git am}}able patch

Comment by Yehonathan Sharvit [ 24/Aug/14 12:56 AM ]

What is the status of this issue?
Why isn't it merged into core.async code?

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

Can we get an updated patch? Thanks.

Comment by Travis Vachon [ 14/Oct/14 2:41 PM ]

updated patch

Comment by David Nolen [ 14/Oct/14 7:33 PM ]

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





[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-96] FixedBuffer's full checking in cljs Created: 13/Oct/14  Updated: 13/Oct/14

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

Type: Defect Priority: Minor
Reporter: Nguyễn Tuấn Anh Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File cljs-fixed-buffer-overflow.patch    
Patch: Code and Test

 Description   

In the cljs implementation of fixed buffer, "full?" uses "=" instead of ">=". This makes it incorrect after an overflow.






[ASYNC-94] Allow user supplied executor/thread-pool (and potentially other options) to be used in go and thread macros Created: 09/Oct/14  Updated: 09/Oct/14

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

Type: Enhancement Priority: Major
Reporter: Max Penet Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Right now thread pools used by core.async are defined as globals, they are shared by all go or thread macro on their respective pools:

see https://github.com/clojure/core.async/blob/ac0f1bfb40237a18dc0f03c0db5df41657cd23a6/src/main/clojure/clojure/core/async.clj#L391-L411
and https://github.com/clojure/core.async/blob/ac0f1bfb40237a18dc0f03c0db5df41657cd23a6/src/main/clojure/clojure/core/async/impl/dispatch.clj#L16

It would be very useful to have more control over this, hopefully not via a simple setter, like the one we have in core for agents (set-agent-send-executor!), since it only allows one pool to be used at a time.
One possible solution would be to do that via an option map parameter to thread-call, and/or some other mechanism for go blocks (go-call with the same kind of signature). Making this parameter a map would also allow to further extend internals in the future, if necessary, without requiring heavy changes to the API.






[ASYNC-32] onto-chan retains head of input sequence causing OutOfMemoryError Created: 06/Nov/13  Updated: 07/Oct/14

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

Type: Defect Priority: Major
Reporter: Brian Lubeski Assignee: Unassigned
Resolution: Unresolved Votes: 1
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.





[ASYNC-67] Can we get a generic sink operation? Created: 09/May/14  Updated: 07/Oct/14

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

Type: Enhancement Priority: Minor
Reporter: Ghadi Shayban Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None

Approval: Triaged

 Description   

Can we get a generic sink operation?

(defn sink
 "Fully consumes and discards a channel, applying f to each val. Returns a channel that
  closes when ch is fully drained"
 [f ch]
 (go-loop []
   (when-some [v (<! ch))]
     (f v)
     (recur))))





[ASYNC-91] 'and' does not short circuit within go block in clojurescript Created: 14/Sep/14  Updated: 25/Sep/14

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

Type: Defect Priority: Minor
Reporter: Jan Krueger Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None
Environment:

core.async 0.1.338.0-5c5012-alpha



 Description   

I have the following piece of ClojureScript code within a go block:

(cond
(and (vector? x) (= (first x) :some-key)) ...)

This generates the following piece of JavaScript code for the cond case:

if (40 === f) { return d = b[9], f = cljs.core.vector_QMARK_.call(null, d), d = cljs.core.first.call(null, d), d = cljs.core._EQ_.call(null, d, new cljs.core.Keyword(null, "some-key", "some-key", -978969032)), cljs.core.truth_(f && d) ? b[1] = 42 : b[1] = 43, new cljs.core.Keyword(null, "recur", "recur", -437573268); }

This looks to me like both and arguments would actually get evaluated. As a result my code crashes whenever it hits this cond case and 'x' is not seqable.



 Comments   
Comment by Francis Avila [ 25/Sep/14 2:52 AM ]

CLJS-864 is likely the same issue. (It also has a small test project to reproduce.)





[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-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-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-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-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-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-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-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-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-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-61] Exceptions thrown inside go/thread blocks propagate up and out of ThreadPoolExcecutor Created: 24/Mar/14  Updated: 06/Aug/14

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

Type: Enhancement Priority: Minor
Reporter: Howard Lewis Ship Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: exceptions
Environment:

core.async 0.1.267.0-0d7780-alpha on JDK 1.7



 Description   

If a go or thread blocks throws an exception, there is nothing in Clojure to catch and handle (or report) the exception. Instead, it propagates up to the ThreadExcecutor which invokes its NO-OP afterExecute() method and is re-thrown, ultimately being displayed on the System.err:

Exception in thread "async-dispatch-32" java.lang.IllegalStateException: Fall down, go boom!
at flashiz.resources.orders$index.invoke(orders.clj:26)
at clojure.lang.Var.invoke(Var.java:411)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.core$apply.invoke(core.clj:617)
at io.aviso.rook$rook_dispatcher.invoke(rook.clj:225)
at flashiz.async$wrap_sync_handler$fn__9005.invoke(async.clj:34)
at flashiz.resources$authorize_async_rook_middleware$fn_9356$fn9402$state_machine3245auto__9403$fn_9405.invoke(resources.clj:21)
at flashiz.resources$authorize_async_rook_middleware$fn_9356$fn9402$state_machine3245auto___9403.invoke(resources.clj:21)
at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:945)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:949)
at clojure.core.async.impl.ioc_macros$take_BANG_$fn__3261.invoke(ioc_macros.clj:958)
at clojure.core.async.impl.channels.ManyToManyChannel$fn__2256.invoke(channels.clj:80)
at clojure.lang.AFn.run(AFn.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)

It would be nice if execution of the go/thread block was wrapped in an exception handler that delegated to a default function to report the exception. My goal is to be able to alter that function to report it more nicely and/or write it to a persistent log file.



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

Patches on ASYNC-76 have been applied and exceptions will now flow up to the top of the thread, where they can be caught by the standard Thread uncaught exception handler mechanism or ultimately by the default uncaught exception handler, which can be set for the application. There may still be further changes to support exception handling in thread/go.





[ASYNC-71] exception behavior for thread macro is hard coded Created: 15/May/14  Updated: 06/Aug/14

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

Type: Enhancement Priority: Major
Reporter: Howard Lewis Ship Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: exceptions
Environment:

0.1.278.0-76b25b-alpha



 Description   

Currently, the thread macro's behavior when an exception occurs is to print the exception (with println), and swallow it.

Although I make a habit of wrapping a try around code inside a thread form, I still find this a bit limited; it would be nice if there was a function that could be dynamically bound, that handled the case of an exception inside a thread.



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

Patches on ASYNC-76 have been applied and exceptions will now flow up to the top of the thread, where they can be caught by the standard Thread uncaught exception handler mechanism or ultimately by the default uncaught exception handler, which can be set for the application. There may still be further changes to support exception handling in thread/go.





[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-83] Taking from channels in anonymous functions inside go-loops does not work Created: 05/Aug/14  Updated: 05/Aug/14

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

Type: Defect Priority: Minor
Reporter: Joel Knighton Assignee: Unassigned
Resolution: Unresolved 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.





[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-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-79] (ClojureScript) go macro not correctly transforming (case) within a macro Created: 23/Jul/14  Updated: 23/Jul/14

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

Type: Defect Priority: Major
Reporter: Tom Locke Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: cljs, macro
Environment:

[org.clojure/clojure "1.6.0"]
[org.clojure/clojurescript "0.0-2234"]
[org.clojure/core.async "0.1.303.0-886421-alpha"]


Attachments: File core_async_bug.tgz    

 Description   

(case-let) is a macro to handle messages of the form [:message-tag, arg1, arg2, ...] with the arguments bound to local variables. It fails to work correctly when used within a go block. Note that a simple macro with a case, e.g. (defmacro my-case [expr & cases] `(case ~expr ~@cases)) does work.

(Sample project attached)

(case-let) definition:

(ns core-async-bug.macros)

(defmacro case-let [expr & cases]
  (let [msg (gensym)]
    `(let [~msg ~expr]
       (case (first ~msg)
         ~@(apply concat (for [[key [args & body]] (partition 2 cases)]
                    [key `(let [~args (rest ~msg)] ~@body)]))))))

ClojureScript test code:

(ns core-async-bug.core
  (:require-macros [cljs.core.async.macros :refer [go]]
                   [core-async-bug.macros :refer [case-let]])
  (:require [cljs.core.async :refer[<! put! chan]]))

(enable-console-print!)

; go block with manual case + lets - works
(let [c (chan)]
  (go
    (let [msg (<! c)]
      (case (first msg)
        :a (let [[x] (rest msg)] (println "First :a" x))
        :b (let [[y] (rest msg)] (println "First :b" y)))))
  (put! c [:b 123]))

; case-let outside of go - works
(case-let [:b 123]
  :a ([x] (println "Second :a" x))
  :b ([y] (println "Second :b" y)))

; case-let inside go - broken
(let [c (chan)]
  (go
    (case-let (<! c)
      :a ([x] (println "Third :a" x))
      :b ([y] (println "Third :b" y))))
  (put! c [:b 123]))

Browser console output:

Second :b 123
First :b 123
Third :a 123          <-- Should not be there!
Third :b 123


 Comments   
Comment by Tom Locke [ 23/Jul/14 3:46 AM ]

More discussion here: https://groups.google.com/forum/#!topic/clojurescript/w21nNWkKR-c

Comment by Tom Locke [ 23/Jul/14 1:58 PM ]

I've discovered an easy workaround for this problem. During macro-expansion core names like case become fully qualified, i.e. cljs.core/case, and it seems that the go macro then fails to recognise the case as such. Replacing case with ~'case in the definition of let-case fixes the problem.

I would hope this leads to an easy fix for someone who knows the core.async codebase.

The working macro is:

(defmacro case-let [expr & cases]
  (let [msg (gensym)]
    `(let [~msg ~expr]
       (~'case (first ~msg)
         ~@(apply concat (for [[key [args & body]] (partition 2 cases)]
                    [key `(let [~args (rest ~msg)] ~@body)]))))))




[ASYNC-78] deadlock in multi catch Created: 05/Jul/14  Updated: 05/Jul/14

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

Type: Defect Priority: Major
Reporter: Lars Bohl Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
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.






[ASYNC-77] StackOverflowError in go macro with cemerick.cljs.test (CLJS) Created: 04/Jul/14  Updated: 04/Jul/14

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

Type: Defect Priority: Minor
Reporter: Daniel Skarda Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

[org.clojure/clojure "1.6.0"]
[org.clojure/core.async "0.1.303.0-886421-alpha"]
[org.clojure/clojurescript "0.0-2261"]
[com.cemerick/clojurescript.test "0.3.1"]



 Description   

I got an StackOverflowError during compilation of CLJS tests using clojurescript.test from Chas Emerick.

I narrowed the problem to following code:

(ns async.overflow.cljs
  (:require-macros [cljs.core.async.macros :refer [go]]
                   [cemerick.cljs.test :refer [deftest is]])
  (:require [cemerick.cljs.test]))

(deftest foobar
  (go
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))))

If you do not get the exception, try to increase number of repetitions of 'is' call.

I was not able to replicate the issue in CLJ. cemerick.cljs.test/is macro is probably far more complex than original CLJ version in clojure.test/is.






[ASYNC-74] Provide a chan? function to determine if a given var is a channel Created: 23/Jun/14  Updated: 30/Jun/14

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

Type: Enhancement Priority: Major
Reporter: Reno Reckling Assignee: Unassigned
Resolution: Unresolved Votes: 2
Labels: None

Attachments: File drupp-async-74.diff    

 Description   

When using channels, for example for streaming http bodies, it would be really helpful if there would be a chan? function to check whether a given var is a channel or not.

Aleph already does it like that in it's http-server/client implementation using lamina channels and it feels quite consistent.

It would of course also be more consistent with the rest of clojure to provide a type checking function for basic objects.



 Comments   
Comment by David Rupp [ 30/Jun/14 9:58 AM ]

Implement chan? predicate.

Comment by Timothy Baldridge [ 30/Jun/14 10:50 AM ]

I'm in favor of this, but last time I asked Rich about it his quote was "do you want a predicate for every single interface?".

Due to the implementation of core.async you'd probably need two additional predicates. One for read-port? and write-port?. You can use (satisfies? clojure.core.async.impl.protocols/ReadPort ...) but that's an internal implementation, so I'd rather have a new predicate than to tell people to touch the innards of core.async. But this call is up to Rich.

Comment by Reno Reckling [ 30/Jun/14 11:07 AM ]

I understand that reasoning. But then we would have to step up on documentation and provide a way to easily determine which interfaces are implemented by the return values of for example (chan). For me, going into the innards of core.async and trying to determine which interfaces I want, especially on very basic things like a channel, is not a user friendly approach at all.





[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-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-54] MAX-QUEUE-SIZE has a wrong type-hint Created: 11/Feb/14  Updated: 23/Jun/14

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

Type: Defect Priority: Trivial
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Unresolved 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.





[ASYNC-70] documentation of thread macro should include behavior of nil (closes the channel) Created: 15/May/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: Howard Lewis Ship Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: reader
Environment:

0.1.278.0



 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.





[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-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-58] mult channel deadlocks when untapping a consuming channel whilst messages are being queued/blocked Created: 20/Feb/14  Updated: 23/Jun/14

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

Type: Defect Priority: Major
Reporter: Mathieu Gauthron Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: deadlock, mult, untap
Environment:

Mac 10.7.5; java version "1.7.0_40"; [org.clojure/clojure "1.5.1"]; [org.clojure/core.async "0.1.267.0-0d7780-alpha"]; Tested with cider and emacs 24.3


Approval: Triaged

 Description   

I have two (or more) listeners tapped onto a mult channel. I want to use them all then have one (or more) of them to leave at will without blocking the other consumer(s) or the publisher. Initially they work fine until one of them wants to stop listening. I thought the listener which drops out needs to (be a good citizen and) untap its channel from mult (otherwise a deadlock is systematic). However if messages are put into the mult before the leaving listener has had a chance to untap its channel, it creates a deadlock on the main thread (which is putting more messages simultaneously). I do not find a way to guarantee that I can untap the channel in time to avoid this race condition.

Once I have reproduced the deadlock, the repl is frozen until I interrupt with ctrl-c.
I have also tried to close the tapped channel before untapping it but the result was the same.

In the following snippet, the last (println "I'm done. You will never see this") is never reached. The publisher and the remaining consumer (consumer 1) are deadlocked even though consumer 2 was trying to leave in good terms.

(require '[clojure.core.async :refer (chan go <! >!! mult tap untap)])
(let [to-mult (chan 1)
      m (mult to-mult)]

  ;;consumer 1
  (let [c (chan 1)]
    (tap m c)
    (go (loop []
          (when-let [v (<! c)]
            (println "1 Got! " v)
            (recur))
          (println "1 Exiting!"))))

  ;;consumer 2
  (let [c (chan 1)]
    (tap m c)
    (go (loop []
          (when-let [v (<! c)]
            (when (= v 42)  ;; exit when value is not 42
              (println "2 Got! " v)
              (recur)))
          (println "2 about to leave!")
          (Thread/sleep 5000) ;; wait a bit to exacerbate the race condition
          (untap m c) ;; before unsubscribing this reader
          (println "2 Exiting."))))

   (println "about to put a few messages that work")
   (doseq [a (range 10)]
     (>!! to-mult 42))
   (println "about to put a message that will force the exit of 2")
   (>!! to-mult 43)
   (println "about to put a few more messages before reader 2 is unsubscribed to show the deadlock")
   (doseq [a (range 10)]
     (println "putting msg" a)
     (>!! to-mult 42))
   (println "I'm done. You will never see this"))
about to put a few messages that work
2 Got!  42
1 Got!  42
2 Got!  42
1 Got!  42
1 Got!  42
2 Got!  42
1 Got!  42
1 Got!  42
2 Got!  42
2 Got!  42
2 Got!  42
2 Got!  1 Got!  42
422 Got!  42

1 Got!  42
1 Got!  42
2 Got!  42
1 Got!  42
about to put a message that will force the exit of 2
1 Got!  42
2 Got!  about to put a few more messages before reader 2 is unsubscribed to show the deadlock
42
putting msg 1 Got!  0
2 about to leave!
43
1 Got!  42
putting msg 1
putting msg 2
putting msg 3
1 Got!  42
2 Exiting.


 Comments   
Comment by Ghadi Shayban [ 22/Apr/14 10:18 AM ]

Mathieu, this is probably expected. It's important to note that to guarantee correct ordering/flow when using a mult, you should enforce it on the source/producer side of the mult, and not asynchronously on the tap side.

Mult will deref a stable set taps just before distributing a value to them, and does not adjust dynamically during value distribution except when a tap has been closed [1]. If you would like to stably untap without closing the tap you can/should let the 'producer' do it in an ordered fashion in between values on the input channel.

Knowing that a put occurred to a closed channel is new on release 0.1.278.

In general, walking away on the consuming side of a channel is tricky. Depending on the semantics of your processes, if the producer side of a channel isn't aware that a close! can happen from the consumer side, you might have to launch a draining operation.

(defn drain [c] (go (when (some? (<! c)) (recur))))

Golang disallows closing a read-only channel FWIW [2]

Better documentation is probably warranted.

[1] https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async.clj#L680-L682
[2] http://golang.org/ref/spec#Close





[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-4] Record literals become ordinary maps Created: 15/Jul/13  Updated: 23/Jun/14

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

Type: Defect Priority: Major
Reporter: Alex Miller Assignee: Unassigned
Resolution: Unresolved 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.





[ASYNC-73] try-catch-finally broken inside go-blocks Created: 21/Jun/14  Updated: 21/Jun/14

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

Type: Defect Priority: Major
Reporter: Moritz Ulrich Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

clojure 1.6.0, clojurescript 0.0-2234, core.async 0.1.303.0-886421-alpha1



 Description   

The following will cause the failed assertion (ioc_helpers.cljs:155)
when evaluated as a whole, and will correctly catch the Error when
just the `try' gets evaluated. The `finally' block runs only if the
inner block is evaluated:

(go
  (try
    (throw (js/Error. "asdf"))
    (catch ExceptionInfo e
      (println "ExceptionInfo"))
    (catch js/Error e
      (println "js/Error"))
    (finally
      (println "finally"))))

Another notable observation is that changing the order of the `catch'
blocks will change the behavior: If the (catch js/Error ...) is the
first catch block, it will work just as expected.






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

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

Type: Enhancement Priority: Major
Reporter: Timothy Baldridge Assignee: Unassigned
Resolution: Unresolved 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.





[ASYNC-69] How to better communicate "mix" lifecycle wrt coordination Created: 09/May/14  Updated: 09/May/14

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

Type: Enhancement Priority: Minor
Reporter: Timothy Baldridge Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Approval: Vetted

 Description   

Confusion regarding 'mix' lifecycle. Users have a false expectation that a mix's output should magically close when its source channels close, not realizing its a dynamic coordination process. Actually ensuring correctness when using mult/mix/pub isn't so straightforward, people need to control consistency from the producer end, and not ad hoc from the consumer side (e.g. late taps of a mult).






[ASYNC-66] Add drain! to consume and discard a channel Created: 09/May/14  Updated: 09/May/14

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

Type: Enhancement Priority: Minor
Reporter: Ghadi Shayban Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Approval: Vetted

 Description   

Do we want this for consumer walkaway scenarios or something baked into the channel impl?

(defn drain!
 "Fully consumes and discards a channel. Returns a channel that
  closes when ch is fully drained"
 [ch]
 (go-loop []
   (if (some? (<! ch))
     (recur))))





[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-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-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-27] Compilation errors inside go block always reported as first line of block Created: 08/Oct/13  Updated: 09/May/14

Status: Open
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: Unresolved Votes: 2
Labels: errormsgs


 Description   

I've noticed that when there are any errors inside a go block, the line number of the error is always the line containing the go symbol.

I suspect that some meta data on the forms that are converted into a state machine is being lost in the process.

This is quite annoying and quite leaky (in the abstraction sense). It makes it that much harder to track down the source of errors.



 Comments   
Comment by Timothy Baldridge [ 22/Nov/13 2:49 PM ]

Working on this, may be a few weeks out yet.

Comment by Hugo Duncan [ 11/Feb/14 5:18 PM ]

This effects both compilation errors and line numbers in stack trace frames.

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

Completed in CLJ, once we get a tools.analyzer.cljs I'll add this to CLJS as well.





[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-65] Change chan returned from pipe to internal go block out channel Created: 09/May/14  Updated: 09/May/14

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

Type: Enhancement Priority: Minor
Reporter: Ghadi Shayban Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Approval: Vetted

 Description   

Can (pipe src dest close?) return the chan of its internal go block instead of 'dest'? This would provide a useful 'done' channel.






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

Status: Open
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: 0
Labels: cljs

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

 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!





[ASYNC-46] Add optional default channel to 'pub' Created: 09/Dec/13  Updated: 05/May/14

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

Type: Enhancement Priority: Major
Reporter: Steffen Dienst Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-Add-default-channel-for-pub.patch    
Patch: Code and Test

 Description   

If there is no subscriber for a topic the message gets silently dropped. I suggest to add an optional default channel that receives all those messages. The default channel can then be used in scenarios, where the complete set of topics might be unknown beforehand.
This functionality resembles the 'dead letter' pattern in messaging systems.






[ASYNC-49] cljs IOC macro issue with double-dot form Created: 12/Jan/14  Updated: 05/May/14

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

Type: Defect Priority: Major
Reporter: Paul Butcher Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

ClojureScript 0.0-2138
core.async 0.1.267.0-0d7780-alpha



 Description   

This ClojureScript compiles and runs as expected:

(let [circle (dom/getElement "circle")]
  (go-loop [x 20]
    (<! (timeout 10))
    (set! (.-value (.-baseVal (.-cx circle))) x)
    (recur (inc x))))

But if I change the set! line to:

(set! (.. circle -cx -baseVal -value) x)

I get the following error:

Wrong number of args (3) passed to: core$-DOT

For further discussion see https://groups.google.com/d/topic/clojurescript/ONMaEho4K0c/discussion






[ASYNC-39] Processes spawned by mix never terminate Created: 21/Nov/13  Updated: 05/May/14

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

Type: Defect Priority: Minor
Reporter: Leon Grapenthin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: chan, mix
Environment:

"0.1.256.0-1bf8cf-alpha"



 Description   

Once a mix has been created, the go-loop inside mix will always recur. Obviously, input-channels can be unmixed and the output-channel could be closed, but the process would still never terminate.

Probably mixes should support something like (stop) to to make the mix-associated process garbage-collectable. Operations on a stopped mix should probably throw.



 Comments   
Comment by Ghadi Shayban [ 22/Apr/14 10:44 AM ]

On 0.1.278 the mix process terminates when its output channel closes [1].

[1] https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async.clj#L778

Comment by Leon Grapenthin [ 24/Apr/14 3:16 AM ]

Yes, it has been fixed using the new return behavior of put!. (I can't find an option to close this issue)





[ASYNC-55] Notification of items dropped from sliding/dropping buffers Created: 12/Feb/14  Updated: 05/May/14

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

Type: Enhancement Priority: Minor
Reporter: Chris Perkins Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: File drop-notification.diff    
Patch: Code and Test

 Description   

I would like to know when items are dropped from sliding or dropping buffers, so that I can do things like logging and keeping metrics.

The attached patch has one possible mechanism for doing this, by adding an optional second argument to sliding-buffer and dropping-buffer - a one-argument function that will be called with dropped items.



 Comments   
Comment by Ghadi Shayban [ 22/Apr/14 10:41 AM ]

Hi Chris, I think this use-case can be handled the combination of a go process + collection directly without modification to the existing buffer impls. I'd be concerned about making buffers pay for a non-essential field.

I like using the library primitives to make sure they are minimally complete.

(If you really really want to make your own buffer, no one will stop you =) It's still an impl protocol, but it's relatively stable. Just beware that buffer operations run within the context of a channel lock, so make sure to dispatch the overflow function to the async threadpool using dispatch/run).





[ASYNC-57] reify in go macro compile error Created: 20/Feb/14  Updated: 05/May/14

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

Type: Defect Priority: Minor
Reporter: Lijin Liu Assignee: Unassigned
Resolution: Unresolved 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.





[ASYNC-63] Variable called 'new' in vector in go block in CLJS causes "Object has no method 'call'" error Created: 07/Apr/14  Updated: 05/May/14

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

Type: Defect Priority: Minor
Reporter: James Henderson Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bug, cljs
Environment:

ClojureScript 0.0-2202, core.async 0.1.267.0-0d7780-alpha, openjdk 7u51


Attachments: File compiled-cljs.js     File test_cases.clj    

 Description   

I seem to be having trouble with the combination of:

  • a variable named 'new'
  • wrapped in a vector
  • after a <! call in a go block.

Removing any of these conditions seems to work fine.

I've attached a few minimal examples in test_cases.clj and the JavaScript that the first error compiles down to in compiled-cljs.js - the errors occur on line 4 (I think inst_39771 is 21 in this case)

An obvious workaround is not to name the variable 'new'

Please let me know if you need anything more from me, and please go easy on me if this is in the wrong place/badly labelled etc - it's my first Clojure JIRA bug report

Thanks,

James



 Comments   
Comment by James Henderson [ 07/Apr/14 4:07 PM ]

Sorry, just spotted there's a newer release of core.async - I've reproduced this with 0.1.278.0-76b25b-alpha as well.

James





[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-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-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-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-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-12] Add chan? or channel? function to identify a channel Created: 19/Jul/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: 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.





[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-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-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-40] do not transform forms that have :no-transform metadata attached Created: 29/Nov/13  Updated: 30/Nov/13

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

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Interaction between core.match clauses and the core.async transform is undesirable. core.async should respect some hook so that some forms are left alone. For example:

(match [x y]
  [1 2] ...
  [3 4] ...)

All code generated for [1 2] and [3 4] would have this metadata attached to it.



 Comments   
Comment by Rich Hickey [ 30/Nov/13 9:25 AM ]

Can you be more specific? This seems like a bad idea, and I wonder why it's desired.

Comment by David Nolen [ 30/Nov/13 2:12 PM ]

To show how bad the interaction is between core.async and a library like core.match that also generates a lot of code consider the following:

(defn foo [e]
  (match [e]
    [{:type :mouse :client-x x :client-y y}] [x y]
    [{:type :mouse :page-x x :page-y y}] [x y]
    [{:type :touch :page-x x :page-y y}] [x y]
    [{:type :key :char-code c}] c))

Without core.async, core.match produces a reasonable amount of code for this typical use of core.match to efficiently match maps - ~230 lines of pretty printed JavaScript.

But if the user wraps this typical expression in a go block:

(defn foo [in]
  (go (while true
        (let [[e c] (<! in)]
          (match [e]
            [{:type :mouse :client-x x :client-y y}] [x y]
            [{:type :mouse :page-x x :page-y y}] [x y]
            [{:type :touch :page-x x :page-y y}] [x y]
            [{:type :key :char-code c}] c)))))

It generates nearly 4200 lines of pretty-printed JavaScript. I fail to see the value of core.async transforming the optimized conditionals generated by core.match, it just generates 18X more code and the extra generated code is obviously useless - a user is matching a value, they cannot put arbitrary computations in the patterns.

https://gist.github.com/swannodette/7723758





[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-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-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-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-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-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-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-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-6] alts! assumes nth works on ports argument Created: 15/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: 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





[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-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-23] Support channel buffers of unlimited size Created: 10/Sep/13  Updated: 15/Sep/13  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.





[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-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-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-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-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-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-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-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-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-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-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-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-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-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.





Generated at Wed Oct 22 17:00:17 CDT 2014 using JIRA 4.4#649-r158309.