This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-06-02
Channels
- # aleph (5)
- # beginners (112)
- # boot (137)
- # cider (10)
- # cljs-dev (36)
- # cljsrn (2)
- # clojure (118)
- # clojure-argentina (1)
- # clojure-berlin (1)
- # clojure-brasil (3)
- # clojure-dev (4)
- # clojure-italy (2)
- # clojure-nl (13)
- # clojure-russia (23)
- # clojure-spec (5)
- # clojure-uk (53)
- # clojurescript (344)
- # clojutre (1)
- # core-async (65)
- # cursive (9)
- # datascript (7)
- # datomic (28)
- # devops (1)
- # emacs (16)
- # events (1)
- # jobs (5)
- # keechma (18)
- # lumo (56)
- # off-topic (7)
- # om (3)
- # onyx (14)
- # protorepl (21)
- # re-frame (3)
- # reagent (20)
- # ring (12)
- # ring-swagger (9)
- # specter (17)
- # unrepl (14)
- # vim (14)
- # yada (22)
I am wondering why core.async does not provide some functionality similar to async/await in C# and JS. go and <! provides a great foundation, but would it not be a good idea to have something that propagates exceptions as well?
Exceptions are always tricky to handle inside core.async. The growing consensus seems to be: catch the exception and pass it through the channel. When possible, if I have a "top level" I might pass a channel just for exceptions around, and the top-level will async/alts! the real result or the exception.
I really don't like it when I see exceptions being passed on the same channel as values
if the go blocks are "long running" internal async services you communicate with via channels, or if go blocks are a calling convention for asynchronous functions
I like to give go blocks the equivalent of the std file descriptors, an in channel, out channel, and error channel (and maybe a shutdown channel)
but, given how often I see exceptions going on the same channel as values, and people writing wrappers for taking from channels that re-throw exceptions and that sort of thing, I suspect the async function style like what C# is the more common idiom
@hiredman I think that's a good plan, and when I'm green-fielding code, that's a great approach. But I also have a lot of legacy core.async code to work on where my options are more limited.
Is there an easier / more canonical way to transform values coming through a single channel than (async/map a-function [a-chan])
?
you can supply a transducing argument to the channel
(when creating it)
(async/chan N (map f))
if you can’t make the channel yourself, you can use pipe and put the transduce on the to channel
(async/pipe c (async/chan N (map f)))
peregrine.circle=> (require '[clojure.core.async :as >])
nil
peregrine.circle=> (def c (>/chan 4))
#'peregrine.circle/c
peregrine.circle=> (def d (>/chan 4 (map #(doto % println))))
#'peregrine.circle/d
peregrine.circle=> (def p (>/pipe c d))
#'peregrine.circle/p
peregrine.circle=> (= p d)
true
peregrine.circle=> (>/put! c "hello")
true
hello
peregrine.circle=> (>/put! c "world!")
world!
true
Yeah, that makes sense. (async/pipe c (async/chan N (map f)))
seems even clumsier than (async/map f [c])
, though.
well, you don’t need to pipe if you create the chan yourself
I guess some APIs let you create a channel and pass it into something which will put!
to it?
it’s good practice to take a chan as an arg, if you use one
especially now that we have transducers and many buffer types
Perhaps naively, it seems easiest to me to have a function which returns a channel which will have the data
a function that takes a chan as an arg, and promises to write to it, is much more reasonable to me than a function that returns the channel it will write to
It just reads so much more simply to (<! (make-an-http-call))
than to (let [c (chan)] (make-an-http-call c) c)
a good convention is to take the chan as an arg, and also return it - you can also make the arg optional
that’s how pipeline does it (returns the to chan)
that was the point of the (= p d)
in my example
right
but in your case, you would also put a transducer in there
well, you don’t need pipe if you can create the chan, but yeah
So, if async/map
is deprecated (and I wish that was mentioned in the docs), is there a modern equivalent that handles multiple channels?
Specifically, I've fired several HTTP requests, and I'm now combining them into a single piece of data
wait, if you memoized it you would keep getting the same channel back
is that what you wanted?
so if it’s a promise-chan, you aren’t really mapping per se, but calling a function on the single value once present
I guess that’s a kind of mapping
Still not used to using transducers with channels: how do I pick a reasonable value for the buffer size?
if you don’t usually supply a buffer arg, I think 1 would be a safe bet