core.async

(CLJS) and with multiple <! does not short-circuit in go

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Minor Minor
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None
  • Environment:
    org.clojure/clojurescript "1.7.48", org.clojure/clojure "1.7.0-RC1", org.clojure/core.async "0.2.374"

Description

I have an and condition inside a go block, where the two conditions take from channels.
When the first condition returns false, I would expect the second condition not to be checked at all. But, it is.

Here is the code:

(defn cc [x]
   (go 
     (println "cc: " x)
   x))

  (defn foo [x]
    (go (when (and (= :ok (<! (cc x)))
                   (= :ok (<! (cc 2))))
          (print "after and"))))

(foo 1)
(foo :ok)

When running (foo 1), I would expect only cc: 1 to be printed, but actually cc: 2 is printed as well.

Happens only in ClojureScript, not in Clojure core.async.

Activity

Hide
Asher added a comment -

Note: This only happens in ClojureScript. In Clojure it works as expected.

Also, sorry for the poor formatting.. this is my first Jira issue.

Show
Asher added a comment - Note: This only happens in ClojureScript. In Clojure it works as expected. Also, sorry for the poor formatting.. this is my first Jira issue.
Hide
Wang Xing added a comment -

Seems and works abnormal in many cases, not just with <!.
I tested this in:
clojure-1.8.0, clojurescript-1.7.228, core.async-0.2.374.
this test need nodejs with the request module.

(def request (js/require "request"))

Now I try to send request to an unaccessible site: google.
Yes, I can't use google.

(def result-chan (chan))

(request
  "http://www.google.com"
  (fn [err res body]
    (go
      (if (and (not err) (= (.-statusCode res) 200))
        (>! result-chan body)
        (>! result-chan [])))))

the result should be "[]" (the request will timeout make "err" non-nil)

(go
  (println "result:" (<! result-chan)))

but actually I get:
TypeError: Cannot read property 'statusCode' of undefined ...
I have printed err and I am sure it's a JS object in this case, not nil or false. that's why res is undefined.
And it also means the short-circuit for and didn't work.
to make things right, use "if" instead of "and"

(def result-chan (chan))

(request
  "http://www.google.com"
  (fn [err res body]
    (go
      (if (not err)
        (if (= (.-statusCode res) 200)
          (>! result-chan body)
          (>! result-chan []))
        (>! result-chan [])))))

then test it again:

(go
  (println "result:" (<! result-chan)))

work as expected now:

result: []
Show
Wang Xing added a comment - Seems and works abnormal in many cases, not just with <!. I tested this in: clojure-1.8.0, clojurescript-1.7.228, core.async-0.2.374. this test need nodejs with the request module.
(def request (js/require "request"))
Now I try to send request to an unaccessible site: google. Yes, I can't use google.
(def result-chan (chan))

(request
  "http://www.google.com"
  (fn [err res body]
    (go
      (if (and (not err) (= (.-statusCode res) 200))
        (>! result-chan body)
        (>! result-chan [])))))
the result should be "[]" (the request will timeout make "err" non-nil)
(go
  (println "result:" (<! result-chan)))
but actually I get: TypeError: Cannot read property 'statusCode' of undefined ... I have printed err and I am sure it's a JS object in this case, not nil or false. that's why res is undefined. And it also means the short-circuit for and didn't work. to make things right, use "if" instead of "and"
(def result-chan (chan))

(request
  "http://www.google.com"
  (fn [err res body]
    (go
      (if (not err)
        (if (= (.-statusCode res) 200)
          (>! result-chan body)
          (>! result-chan []))
        (>! result-chan [])))))
then test it again:
(go
  (println "result:" (<! result-chan)))
work as expected now:
result: []
Hide
Jacek Tomaszewski added a comment -

Well, the issue happens even for go-blocks without <!, and that is really strange. or is also affected. Here you have an example:

(go
  (if  false (not= 404 (:status (println "SHOULD NOT BE PRINTED 1"))))  ; ok
  (and false (not= 404 (:status (println "SHOULD NOT BE PRINTED 2"))))  ; fail
  (or  true  (not= 404 (:status (println "SHOULD NOT BE PRINTED 2a")))) ; fail
  (if  false (:status (println "SHOULD NOT BE PRINTED 3")))  ; ok
  (and false (:status (println "SHOULD NOT BE PRINTED 4")))  ; ok
  (or  true  (:status (println "SHOULD NOT BE PRINTED 4a"))) ; ok
  )

When you run this code snippet in Clojure, nothing gets printed (as expected).
In ClojureScript, however (tested with newest async version 0.3.443), you'll see SHOULD NOT BE PRINTED 2 and 2a.
Interesting observation: shorter computations (like example 4/4a) behave properly.

Like Wang Xing noticed: using `if` seems a safe way around this bug.

Show
Jacek Tomaszewski added a comment - Well, the issue happens even for go-blocks without <!, and that is really strange. or is also affected. Here you have an example:
(go
  (if  false (not= 404 (:status (println "SHOULD NOT BE PRINTED 1"))))  ; ok
  (and false (not= 404 (:status (println "SHOULD NOT BE PRINTED 2"))))  ; fail
  (or  true  (not= 404 (:status (println "SHOULD NOT BE PRINTED 2a")))) ; fail
  (if  false (:status (println "SHOULD NOT BE PRINTED 3")))  ; ok
  (and false (:status (println "SHOULD NOT BE PRINTED 4")))  ; ok
  (or  true  (:status (println "SHOULD NOT BE PRINTED 4a"))) ; ok
  )
When you run this code snippet in Clojure, nothing gets printed (as expected). In ClojureScript, however (tested with newest async version 0.3.443), you'll see SHOULD NOT BE PRINTED 2 and 2a. Interesting observation: shorter computations (like example 4/4a) behave properly. Like Wang Xing noticed: using `if` seems a safe way around this bug.
Hide
Jacek Tomaszewski added a comment -

I suggest changing issue title to "(CLJS) and/or does not short-circuit in go"

Show
Jacek Tomaszewski added a comment - I suggest changing issue title to "(CLJS) and/or does not short-circuit in go"

People

  • Assignee:
    Unassigned
    Reporter:
    Asher
Vote (4)
Watch (3)

Dates

  • Created:
    Updated: