core.async
Clojure eXchange 2014
David Pollak / @dpp
core.async
and associated librariesNot Spike from My Little Pony
from How to Train Your Dragon (the book).
The
mark of those rebelling against Alvin the Treacherous.
Yes, this talk will contain a lot of seemingly random threads... I hope to pull it together in the end (and in under 50 minutes)
Spike sends messages from Ponyville to Princess Celstia in Equestria... across address spaces...
We can serialize Clojure data and send it to
another address space such that it will have the same
meaning when it's reified!
Thinking asynchronously...
Well...
Nothing is synchronous...
Exception some 'weird' quantum effects...
But...
We humans mostly gloss over asynchronousness.
Any => Unit
: I'm going to the pubX => LAFuture[Y]
: Bruce, I'd like a hug!core.async
:
linear instructions for non-linear execution
Spike: find the book
Pinky: Find Applejack
S&P: Look for gems
aka the gofor
macro
gofor
: for comprehension, go-style
(gofor
[a (foo channel {:thing value :other_thing other_value})]
:let [b (+ a 1)]
[c (baz other_channel)
d (moose third_channel {:p b}
:timeout 45000]
(println a b c)
:error (println &err &at))
[a (foo channel {:thing value :other_thing other_value})]
sends a message to channel
:
{:_cmd "foo"
:thing value
:other_thing other_value
:_return a_created_channel}
Simultaneous dispatch & timeout
(def service-channel (dc/build-service ns))
In the namespace, we define functions:
(sc/defn ^:service get-42 :- sc/Num
([] 42)
([x :- sc/Num] (+ x 42)))
(sc/defn ^:service plus-one :- sc/Num
"Hello"
[x :- sc/Num]
(+ 1 x))
docs (_commands service)]
:let [_ (println "Commands:\n" docs)
Commands:
{get-42 Inputs: ([] [x :- sc/Num])
Returns: sc/Num
Hello, plus-one Inputs: [x :- sc/Num]
Returns: sc/Num}
core.async
core.async
(circ/gofor
:let [other-root (circ/remote-root transport)]
[the-chat-server (locate-service other-root {:service "chat"})]
[_ (add-listener the-chat-server {:the-chan chat-listener})]
(reset! chat-server the-chat-server)
:error (.log js/console "Got error " &err " var " &var)
)
root
(defn make-remote-calls
[]
(circ/gofor
[answer (inc (circ/remote-root transport))]
(do
(swap! app-state assoc :text (str "Remote count: " answer))
(js/setTimeout make-remote-calls 1000)
)
))
root (circ/build-root-channel
{"get" (fn [msg env] @count-atom)
"inc" (fn [msg env]
(swap! count-atom inc))}
{:_cmd "foo"
:thing value
:other_thing other_value
:_return a_created_channel}
(defprotocol Transport
"A transport to another address space"
(remote-root
"Returns a channel that is a way to send messages to
the remote root"
[this])
(close!
"Close the transport"
[this])
(proxy-info "GUID to Proxy functions" [this])
(serialize "Serialize a msg" [this info])
(deserialize "reify a msg" [this info]))
Dragonmark Repo: https://github.com/dragonmark