<< Back to previous view

[ASYNC-123] Channel operations fail in for comprehension. Created: 25/May/15  Updated: 14/Jun/15

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

Type: Defect Priority: Major
Reporter: Christian Weilbach Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bug
Environment:

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



 Description   

``` clojure
(<!! (go (for [a (<! (go [1 2 3]))]
a)))
;=> (1 2 3)
```

works fine. But:

```
(go (for [a [1 2 3]
:let [b (<! (go a))]]
b))
```

1. Caused by java.lang.IllegalArgumentException
No method in multimethod '-item-to-ssa' for dispatch value: :fn

MultiFn.java: 160 clojure.lang.MultiFn/getFn
MultiFn.java: 227 clojure.lang.MultiFn/invoke
ioc_macros.clj: 492 clojure.core.async.impl.ioc-macros/item-to-ssa
ioc_macros.clj: 547 clojure.core.async.impl.ioc-macros/let-binding-to-ssa/fn
ioc_macros.clj: 122 clojure.core.async.impl.ioc-macros/all/fn/fn
ArrayChunk.java: 58 clojure.lang.ArrayChunk/reduce
protocols.clj: 98 clojure.core.protocols/fn
protocols.clj: 19 clojure.core.protocols/fn/G
protocols.clj: 31 clojure.core.protocols/seq-reduce
protocols.clj: 54 clojure.core.protocols/fn
protocols.clj: 13 clojure.core.protocols/fn/G
core.clj: 6289 clojure.core/reduce
ioc_macros.clj: 120 clojure.core.async.impl.ioc-macros/all/fn
ioc_macros.clj: 554 clojure.core.async.impl.ioc-macros/eval22522/fn/fn
ioc_macros.clj: 600 clojure.core.async.impl.ioc-macros/eval22585/fn/fn
ioc_macros.clj: 806 clojure.core.async.impl.ioc-macros/parse-to-state-machine/fn
ioc_macros.clj: 80 clojure.core.async.impl.ioc-macros/get-plan
ioc_macros.clj: 802 clojure.core.async.impl.ioc-macros/parse-to-state-machine
ioc_macros.clj: 1066 clojure.core.async.impl.ioc-macros/state-machine
async.clj: 384 clojure.core.async/go
RestFn.java: 442 clojure.lang.RestFn/invoke
Var.java: 388 clojure.lang.Var/invoke
AFn.java: 160 clojure.lang.AFn/applyToHelper
Var.java: 700 clojure.lang.Var/applyTo
Compiler.java: 6552 clojure.lang.Compiler/macroexpand1
Compiler.java: 6630 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6445 clojure.lang.Compiler/analyze
Compiler.java: 6406 clojure.lang.Compiler/analyze
Compiler.java: 3719 clojure.lang.Compiler$InvokeExpr/parse
Compiler.java: 6646 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6445 clojure.lang.Compiler/analyze
Compiler.java: 6406 clojure.lang.Compiler/analyze
Compiler.java: 5782 clojure.lang.Compiler$BodyExpr$Parser/parse
Compiler.java: 5217 clojure.lang.Compiler$FnMethod/parse
Compiler.java: 3846 clojure.lang.Compiler$FnExpr/parse
Compiler.java: 6642 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6445 clojure.lang.Compiler/analyze
Compiler.java: 6700 clojure.lang.Compiler/eval
Compiler.java: 7130 clojure.lang.Compiler/load
REPL: 1 geschichte.p2p.hooks/eval32348
Compiler.java: 6703 clojure.lang.Compiler/eval
Compiler.java: 6666 clojure.lang.Compiler/eval
core.clj: 2927 clojure.core/eval
main.clj: 239 clojure.main/repl/read-eval-print/fn
main.clj: 239 clojure.main/repl/read-eval-print
main.clj: 257 clojure.main/repl/fn
main.clj: 257 clojure.main/repl
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 67 clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 624 clojure.core/apply
core.clj: 1862 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
interruptible_eval.clj: 51 clojure.tools.nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 183 clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
interruptible_eval.clj: 152 clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn
AFn.java: 22 clojure.lang.AFn/run
ThreadPoolExecutor.java: 1145 java.util.concurrent.ThreadPoolExecutor/runWorker
ThreadPoolExecutor.java: 615 java.util.concurrent.ThreadPoolExecutor$Worker/run
Thread.java: 745 java.lang.Thread/run

Possibly this is due to the function boundaries of go-blocks, but I think it would be nice if this would work similar to the binding for `a`. I have basically one big for-comprehension to map a highly nested seq and rewriting it will make the code much more verbose. Note that I know that I cannot execute channel ops inside the body of the for-comprehension due to the function boundaries in lazy seqs. This is no problem, but I cannot fix the for-comprehension bindings easily.
I played around with extending the -item-to-ssa multimethod, but some pointers of how to fix it properly would be nice. Then I could try to implement a patch.



 Comments   
Comment by Christian Weilbach [ 14/Jun/15 9:11 AM ]

This is actually a problem for many more cases, only a take operation in the first binding works, because the for-comprehension macro in core.clj wraps every following binding in a lazy-seq. The best fix to me seemed to be a custom version of the for-comprehension macro.

I have simplified the macro to remove lazyness and rewritten it with go-loops. This works fairly well, but it is eager and channel operations are sideeffects, so channels representing constants on which iteration happens repeatedly should be put in an immutable collection before (e.g. let binding around the comprehension).

https://github.com/ghubber/geschichte/blob/c57bacdcf8e3335d17dc370941384c559ae80373/src/cljx/geschichte/go_for.cljx#L25





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

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

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

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


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

 Description   

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

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

Crashes with:

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

This works fine with 0.1.338.0-5c5012-alpha.



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

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

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

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

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

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

Patch from the pull request attached.

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

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

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

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

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

Some possible solutions:

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

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

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

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

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

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

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

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

Issue is confirmed on this end. Will look into.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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





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





Generated at Sun Aug 02 19:40:10 CDT 2015 using JIRA 4.4#649-r158309.