This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-08-08
Channels
- # aleph (4)
- # beginners (5)
- # cljs-dev (21)
- # clojure (155)
- # clojure-dev (3)
- # clojure-italy (10)
- # clojure-losangeles (3)
- # clojure-nl (2)
- # clojure-russia (5)
- # clojure-spec (42)
- # clojure-uk (11)
- # clojurescript (170)
- # code-art (1)
- # component (3)
- # core-async (28)
- # cursive (70)
- # data-science (3)
- # datascript (1)
- # datomic (28)
- # emacs (6)
- # gorilla (1)
- # graphql (2)
- # jobs (1)
- # lein-figwheel (4)
- # lumo (7)
- # off-topic (13)
- # om (63)
- # parinfer (66)
- # planck (1)
- # re-frame (22)
- # reagent (2)
- # ring-swagger (53)
- # rum (3)
- # sql (13)
- # test-check (2)
- # unrepl (48)
- # vim (8)
- # yada (33)
Question: Can someone help me understand the error message I’m getting here?
(ns sandbox.async
(:use clojure.core.async))
(<!!
(let [out-mix (mix (chan))
[ch-a ch-b ch-c] [(chan) (chan) (chan)]
n 10]
(admix out-mix ch-a)
(admix out-mix ch-b)
(admix out-mix ch-c)
(go
(dotimes [i n] (>! ch-a (str "A" i)))
(close! ch-a))
(go
(dotimes [i n] (>! ch-b (str "B" i)))
(close! ch-b))
(go
(dotimes [i n] (>! ch-c (str "C" i)))
(close! ch-c))
(go-loop [x (<! out-mix)]
(println x)
(when x (recur (<! out-mix))))))
java.lang.IllegalArgumentException: No implementation of method: :take! of protocol: #'clojure.core.async.impl.protocols/ReadPort found for class: clojure.core.async$mix$reify__25479
at clojure.core$_cache_protocol_fn.invokeStatic(core_deftype.clj:583)
at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:575)
at clojure.core.async.impl.protocols$eval17719$fn__17720$G__17710__17727.invoke(protocols.clj:15)
at clojure.core.async.impl.ioc_macros$take_BANG_.invokeStatic(ioc_macros.clj:983)
at clojure.core.async.impl.ioc_macros$take_BANG_.invoke(ioc_macros.clj:982)
at sandbox.async$eval28394$fn__28656$state_machine__23947__auto____28669$fn__28671.invoke(form-init833577736485949258.clj:14)
at sandbox.async$eval28394$fn__28656$state_machine__23947__auto____28669.invoke(form-init833577736485949258.clj:14)
at clojure.core.async.impl.ioc_macros$run_state_machine.invokeStatic(ioc_macros.clj:973)
at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:972)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invokeStatic(ioc_macros.clj:977)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:975)
at sandbox.async$eval28394$fn__28656.invoke(form-init833577736485949258.clj:14)
at clojure.lang.AFn.run(AFn.java:22)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
that first part of the output indicates to me that you are trying to treat an inner class created by mix as if it were a readable channel
mix expects to take an out chan as an arg, I think you need to read from that out chan (which you currently don’t bind)
haha! barely beat you to it, just by reading a stack trace
well, i knew from the stack trace that this was the case, but i don’t use mixes (hardly ever) so had to see what does what 🙂
I’m just joking anyway - I don’t use mixes either
i’ve mistakenly called protocol functions enough times on something that doesn’t implement the protocol to know that error
awesome, thanks guys!
Okay, that totally fixed it.
That also answers my questions about close semantics when using mixes
@ajmagnifico also, as a general rule, it’s a good pattern to write code that uses channels so that it takes an in-chan and / or out chan as args
that way the calling code can decide how it needs to buffer / xform with transducers / etc.
and you can also simplify your code by not creating your own chans all the time
(which is why mix is accepting a chan arg here for example)
thanks @noisesmith , I understand the words you’re using, but am having a hard time grokking it. Do you know of any examples of this that you could point me to?
In general, you’re just saying ---- if I write functions that make use of channels, then give an in-channel and/or out-channel as a parameter?
@ajmagnifico it’s a design principle - for example what if you wanted to print everything that goes out of the mix
(sorry, new baby at home = not a lot of sleep lately 😄 )
if so, you can do (let [c (chan 10 (map #(doto % println))) m (mix c)] …)
that’s a transducer that adds printing to each item as it comes through the mix, without having two write a bunch of glue code to process the items
and the general idea is if you write code that expects to take a chan as an arg, client code can leverage that
it makes code more extensible
okay, I get what you’re saying
I’m going to keep that in mind as I move forward, and you’ll probably see me in here again asking for feedback at some point