This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-30
Channels
- # aws (4)
- # beginners (143)
- # boot (37)
- # cider (31)
- # cljs-dev (53)
- # clojure (303)
- # clojure-conj (5)
- # clojure-dev (106)
- # clojure-dusseldorf (2)
- # clojure-greece (3)
- # clojure-italy (23)
- # clojure-spec (83)
- # clojure-uk (7)
- # clojurescript (328)
- # core-async (25)
- # cursive (2)
- # datascript (2)
- # datomic (3)
- # emacs (10)
- # hoplon (1)
- # jobs (2)
- # lein-figwheel (1)
- # leiningen (13)
- # luminus (6)
- # off-topic (38)
- # onyx (2)
- # parinfer (13)
- # pedestal (2)
- # portkey (5)
- # re-frame (11)
- # reagent (2)
- # shadow-cljs (61)
- # specter (6)
- # unrepl (60)
- # vim (4)
What's the pattern to create a channel with both a buffer and a timeout? Create a channel with a buffer and then a transducer that reads it into a channel with a timeout?
prob better to alt over the buffer channel and a timeout channel
Yup, that looks sensible. Cheers!
Hello, after reading a good introduction to clojure async I am still some doubts
Hope someone can help me
First of all, and in the context of cljs, when should I use go and when should I don't use it ?
And I'm not clear about what's de difference betwen parked and not parked puts and gets in the context of cljs
javascript doesn’t have threads, so the blocking (anything suffixed with !!
) operations don’t exist in cljs core.async
Perfect, way easier 😃
Than what is the purpose of the go blocks ?
This will probably be helpful: http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html
>>> go is a macro that takes its body and examines it for any channel operations. It will turn the body into a state machine. Upon reaching any blocking operation, the state machine will be ‘parked’ and the actual thread of control will be released. This approach is similar to that used in C# async. When the blocking operation completes, the code will be resumed (on a thread-pool thread, or the sole thread in a JS VM). In this way the inversion of control that normally leaks into the program itself with event/callback systems is encapsulated by the mechanism, and you are left with straightforward sequential code. It will also provide the illusion of threads, and more important, separable sequential subsystems, to ClojureScript.
It’s useful for more simply managing events normally handled by callbacks and for organizing code into separate concurrent subsystems, the “separable sequential subsystems”.
Is it of any use if what I need is cascade http requests ?
With some operations in between
That one is for the browser I'm affraid
So I'm wrapping request.js
I haven’t used cljs with node but this comes up: https://github.com/quile/cljs-http-node
hahaha, yes, I saw both. I'll go with my own wrapper this time for learning purposes
But another doubt arises, about what is better practice: To return a closed channel from every async function (meant to be executed once), or to accept a channel and push the events to it ?
Do you mean to accept a channel and create one if it does not exist ? And at the end, return that channel ?
But then you sholud not close it, because you don't know what people is going to do with it
Right - some of the core.async fns which accept a channel to use for output have an optional close?
argument for that reason
hahaha, that seems to be a common answer for clojurians
Nothing seems right or wrong
I usually just do what fits the immediate known use-case and either learn that’s fine or have to do a small refactor later. Right now I have a situation where I’m not sure how far to extend the boundary between core.async and the rest of my application — do I keep returning channels and offering blocking & parking variants of fns to support composition or do I hide it at some point?
Probably you will not know what is better until it bites you on the ass
I usually favor composition at all cost
Yup - but fixing it won’t take long so the cost of making the mistake, learning & fixing the mistake is low
I have some vector [1 2 3], how do I assoc with the map {} such that I get {:1 nil, :2 nil, :3 nil} ?
Sure is
Which takes two sequences and zips them up into a map. So a sequence of nils might be useful. So look into repeat and repeatedly
(repeat n nil)
Zipmap will stop at the shortest sequence so you would never want to omit your actual data because you ran out of place holder nils
Good call
You can't call repeatedly on nil, it's a null pointer exception 😕
Ah, (repeatedly #(nil))
Which, of course, you don't here
And look at iterate which is always fun to use. It's not useful for you here but it's in that class of functions which make a sequence like here
One question
How can I pass different values to a function based on an if condition?
I mean, I have user and pass, then pass auth object + handler, if I don't have them just pass the handler
That is more or less what I'm trying
Should i not use defn ?
Then My automatic indentator is getting crazy about this
As you can see here it is understanding the let statement as part of the parameters list
(defn Get
([url] (Get url nil nil))
([url usr pass
(let [c (chan)
Yes, changing the indentation worked
This is my final version, which I don't like much. I would prefer to put the second let on a newline, but then my automatic paren tool will understand it as part of the parameters, or close the function at the same line
(defn Get
([url] (Get url nil nil))
([url usr pass] (let [c (chan)]
(if (and usr pass)
(req/get url (makeAuth usr pass) (handler c))
(req/get url (handler c)))
c)))
parinfer, on VSCode
Finally!!!
(defn Get
([url] (Get url nil nil))
([url usr pass]
(let [c (chan)]
(if (and usr pass)
(req/get url (makeAuth usr pass) (handler c))
(req/get url (handler c)))
c)))
The problem was the usage of tab for indenting, which by default inserts two spaces
Seems that it was required to use one
Hola #beginners! Just wanted to share a small piece of Clojure code that uses a Java library, in order to demystify interop calls a bit. The goal of the code is to turn a UUID into a human readable mnemonic.
The code takes:
#uuid "59c5c57b-c0e1-4ab5-a941-814a66cfc8dc"
and returns "flush comfort galaxy limb believe food pink coral engine cushion vendor rib"
Then we can use test.check to run generative tests against the third party library, to make sure that all UUIDs can be read perfectly from their generated mnemonics.
You can check whether it works manually:
;;; does it manually work?
(require '[clojure.string :as str])
(let [uuid (UUID/randomUUID)
mnemonic (-> uuid uuid->bytes bytes->mnemonic)
read-uuid (-> mnemonic mnemonic->bytes bytes->uuid)]
{:original uuid
:human-readable (str/join " " mnemonic)
:roundtrip read-uuid
:equivalent? (= read-uuid uuid)})
(require '[clojure.test.check.generators :as gen])
(require '[clojure.test.check :refer [quick-check]])
(require '[clojure.test.check.properties :refer [for-all]])
;; generator for random 16-byte arrays
(def gen-byte-array (gen/fmap byte-array (gen/vector gen/byte 16)))
;; property that asserts that a byte array can "roundtrip" through the mnemonic
(def roundtrip (for-all [a gen-byte-array]
(= (seq a)
(seq (-> a bytes->mnemonic mnemonic->bytes)))))
(quick-check 5000 roundtrip)
(Subtle point in the roundtrip property -- you have to call seq
on the byte arrays because by default in Java byte arrays are compared for equality by reference or object identity, not by value like in clojure)
I hadn’t actually realized this. Should I think of identical?
as reference equality and =
as value equality for cljs collections? I guess I don’t often compare collections but it could be a surprising performance gotcha.
That is the correct mental model. It's not a performance gotcha as much as it is a correctness gotcha
= in Clojure delegates to .equals for some java classes. Which for byte arrays does reference equality
i assume roughly the same thing in cljs? i don’t actually build stuff in clojure atm
Hey #beginners , I have a small question. Does map always return a list if the result is linear in nature?
Example: (map inc [1 2 3]) returns a list
that's right. map
is a sequence function. All sequence functions call seq
on their input
to coerce their input into a seq (that's why you can pass a vector, and it works happily)
if you want a vector at the end, there is a function mapv
, or you can call (into [] .....)
at the end of a collection "pipeline"
But don't use mapv everywhere -- if you have a bunch of operations in a pipeline (like map/filter/partition/etc.) you only need to pour into a []
at the last step
thanks a lot @ghadi
Why is this a compilation error? It sure looks like recur is in the tail position to me
(defn build-sitemap
[chan timeout-chan]
(loop []
(async/alt!!
timeout-chan @sitemap
chan ([url] ((client/get url {:async? true}
(fn [raise] nil)
(fn [response] (apply-response-to-state response url)))
(recur))))))
(i.e. I'd like to handle messages to the channel by invoking a function with a callback on them and then invoking the function that listens to the channel again)
<It isn't in the tail position, I wrongly double-bracketed the client/get stuff 😕 >
I hadn’t actually realized this. Should I think of identical?
as reference equality and =
as value equality for cljs collections? I guess I don’t often compare collections but it could be a surprising performance gotcha.
@lee.justin.m Pretty much. Here's the doc string for identical? "Tests if 2 arguments are the same object"
While = is the same as Java's equals method, which is more or less "is this value the same as this other value?"
Let the philosophers argue over right and wrong, we programmers have our hands full with equality.
In core.async, what is the best way to race two channels?
Following this blog post: http://subhasingh.com/blog/How-to-Setup-Datomic-Free/
I get this error: FileNotFoundException Could not locate datomic/api__init.class or datomic/api.clj on classpath. clojure.lang.RT.load (RT.java:456)
What do you mean "in a project file"? How are you running that file?
Sounds like your Atom REPL isn't using the same setup as your Leiningen project.
Do you have multiple projects in Atom? The default is to start the REPL from the first project listed.
You're on a Mac?
And using Opt-Cmd-l to start your REPL?
If you open the project.clj
for which you want a REPL (your Datomic API project), then Opt-Cmd-L (shift-l) will create a REPL from that project.clj
file.
(or you can right-click > proto-repl
> Start REPL from open project.clj/build.boot
)
There's a #protorepl channel if you need more extensive help with Atom/ProtoREPL.
Welcome back to Clojure BTW 🙂
Yeah, it catches everyone out at least once when they have multiple projects.
I have multiple projects -- but I use Boot for everything and you can load new dependencies into the REPL easily with Boot so it's much easier to start a generic REPL and then just eval forms to add the dependencies you want at runtime.
How good is the experience with atom?
Clj or cljs?
@rdanielo Great! ProtoRepl, Parinfer, Joker linter, rainbow paren and you’re good to go. When Atom first came out it was unusable, now its good.
I'll give it a go, VSCode is not being a good experience
@rdanielo I switched from Emacs to Atom/ProtoREPL about 18 months ago (I believe) after many years of Emacs. I really like it.
Is anyone here familiar with Android development with re-natal (or other things)? I am trying to get started and would love any tips. Currently, I have the starter project loading on a device through USB, but am trying to get figwheel to connect.