This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-09
Channels
- # announcements (5)
- # babashka (1)
- # beginners (116)
- # calva (139)
- # cider (11)
- # clara (2)
- # clj-kondo (13)
- # clojure (247)
- # clojure-dev (18)
- # clojure-europe (5)
- # clojure-france (2)
- # clojure-italy (2)
- # clojure-nl (7)
- # clojure-spec (24)
- # clojure-uk (34)
- # clojurescript (41)
- # cursive (11)
- # data-science (2)
- # datomic (33)
- # emacs (10)
- # events (3)
- # fulcro (134)
- # graphql (9)
- # jackdaw (3)
- # jobs (1)
- # joker (20)
- # kaocha (3)
- # leiningen (7)
- # luminus (2)
- # malli (3)
- # music (1)
- # pedestal (7)
- # re-frame (25)
- # remote-jobs (7)
- # ring (7)
- # shadow-cljs (85)
- # spacemacs (13)
- # testing (2)
- # tools-deps (60)
- # xtdb (11)
- # yada (7)
Hey! I’m reading Programming Clojure
and there’s this snippet: “Clojure is high signal, low noise…”
I’m having a hard time to understand this. Where can I be familiar with these terms? What’s the definition of a high signal and low noise language?
It is a figure of speech meaning the amount of code it takes to perform some action is very small with very little outside what is minimally required
It is an analogy to https://en.m.wikipedia.org/wiki/Signal-to-noise_ratio where for example in Java to print something out, the "signal" might be System.out.println("foo")
and the "noise" would be the class and method around it
@mzavarella It's going to depend on how you identify your primary key, but what I've seen is to run an update!
based on the PK and if that returns zero rows updated, do an insert!
with the PK assoc
'd into the data -- but you really need to wrap the insert!
in try
/`catch` in case another thread also attempts the insert (and this is assuming you have a unique constraint on your PK so a second insert will fail), and if the insert fails, because of that constraint, you need to retry the upsert.
Reading around, it looks like you might be able to just do INSERT ... ON DUPLICATE KEY UPDATE
but I'm not sure how that would work with auto-generated PKs...
See https://www.xaprb.com/blog/2006/02/21/flexible-insert-and-update-in-mysql/ for more options.
(non-standard SQL caveats, not available in all versions of MySQL caveats, etc, etc)
If you have non-primary (keys) only, you can still do the update-or-insert approach (assuming auto-gen'd PK).
Anyone played with claypoole? I have a pool of processes doing http document uploads. They're all using a token stored in an atom, when the token expires I'd really like one Thread to know that it has the job of updating the token, I guess it won't do any really harm for them all to update the atom but it just doesn't seem right, should I bracket the token check/update in some other way?
@zugnush Perhaps you could push the check/update into an agent so that piece of work would be single threaded?
thanks Sean, I think might be what I need, I had it in my head that i needed to check the thread id somehow but that sounds much better. Ta. Loving jdbc-next btw.
Cool. Best channel to ask Qs about next.jdbc
is #sql to make sure I see it. Always happy to hear feedback on it (and on its docs).
Quick spec question…
(require '[clojure.spec.alpha :as s])
(require '[clojure.test.check.generators :as gen])
(s/def ::non-map #(not (map? %)))
(gen/generate (s/gen ::non-map))
… results in an interesting error in my environment:
1. Unhandled clojure.lang.ExceptionInfo
Spec assertion failed.
Spec: nil
Value: nil
Problems:
alpha.clj: 282 clojure.spec.alpha/gensub
What am I doing wrong?I am taking a stab in the dark here, but I suspect that the built in generators do not handle the case where you have a function you wrote (`#(not (map? %))` in this case) as the spec predicate. Probably you would need to write your own generator function for such a spec.
I think that is correct: (s/gen #(not (map? %)))
says that its unable to construct a generator 🙂
@alexmiller FYI, I find a tool who already do the job https://github.com/hagmonk/find-deps
Hi, I learned some (very little) clojure before, and am in the progress of relearning it. I was comparing its expressiveness with some other languages (python and go), but so far I don't find it that more expressive as people claimed. Let's take 4clojure problem 41 for example:
;; Drop Every Nth Item - Easy
;; Write a function which drops every Nth item from a sequence.
Here is my clojure version
(defn to-vector [& rest]
rest)
(defn keep-index? [n [index _]]
(not
(zero?
(mod (inc index) n))))
(defn my-drop-every [coll n]
;; Use transduers to transform the collection
(into []
(comp (map-indexed to-vector)
(filter (partial keep-index? n))
(map second))
coll
))
but it's much longer than python version:
def my_drop_every(coll, n):
return [x for idx, x in enumerate(coll)
if (idx + 1) % n != 0]
and even the go version is not so bad
func MyDropEvery(coll []int, n int) []int {
newcoll := make([]int, len(coll))
for index, i := range(coll) {
if index % n != 0 {
newcoll = append(newcoll, i)
}
}
return newcoll;
}
(defn drop-every
[n coll]
(mapcat drop-last (partition n coll)))
(drop-every 4 (range 32))
;; => (0 1 2 4 5 6 8 9 10 12 13 14 16 17 18 20 21 22 24 25 26 28 29 30)
need to consider inputs thats not equaly divided by four though
partition-all?
Thx! Take a while to reason about it. It's clever to first partition
then drop-last
.
Is this the idiomatic way to write clojure code?
It's how I would break down the problem. It's not complete and har some flaws with it. As @danieleneal says partition-all is a better tool. Something like
(defn drop-every
[n coll]
(->> (partition-all n coll)
(mapcat (partial take (dec n)))))
Should give a more robust solution@UP90Q48J3 You can follow people who are good at Clojure on 4clojure and compare your solution to theirs.
@UHHG094TS thx! Yeah that's sooo helpful.
(for [[i el] (map list (rest (range)) cool) :when (not (zero? (mod i n)))] el)
is pretty much the same as your python versionDo you find it any more readable when split over multiple lines?
(for [[i el] (map list (rest (range)) cool)
:when (not (zero? (mod i n)))]
el)
(assuming I can do Slack formatting correctly)
that's a matter of familiarity :) it took me longer to figure out how to read your python version than rewriting it in clojure
If you consider that is much less readable than the Python version, then I would wonder how long you have been programming in Python vs. how long you have been trying Clojure. Familiarity does take some time.
Thx! I have been using python daily for years. That make sense guys -- I guess I was in the typical trap of "Simple made easy"
This is like magic to me! Would you really write this kind of code in a production team project? Not offense intended.
Probably not, as I try to avoid apply
and concat
for performance reasons, unless I know that the size of the collection is fairly bounded
I'd probably write this: https://clojurians.slack.com/archives/C053AK3F9/p1570628444019300
(defn drop-every [n coll]
(mapcat (fn [x i]
(when (not= (mod x n) 0)
[x]))
coll
(range)))
I like this version! And (not= x 0)
is better than (not (zero? x)
. Didn't know mapcat would ignore nil
in the flatten step
yep @U060FKQPN could explain better but nil will work like an empty sequence, so can be used in concat etc
You can use function literals to make it even more concise,
(defn drop-nth [n coll]
(mapcat #(when (not= (mod %2 n) 0) [%1])
coll
range))
Clojure is just as concise as Python IMO with far less syntactic tricks (fn literals being one of them) making it more readable at same levels of familiarity.Thx @U883WCP5Z! This is really cool example.
Also can be done without mapcat and the extra collections which are expensive over large inputs
(->> (map (fn [i x]
(when-not (zero? (mod (inc i) n))
x))
(range)
coll)
(filter some?))
That being said though, concision is not really a core value prop of Clojure. Simplicity, Power and Focus are Clojure's real strong suits.
the partition version is neat, both are idiomatic approaches imo
One thing I’d say is that for this type of thing, there’s not really that much to choose Clojure over any other language. The python solution here is definitely more readable than most of our suggestions. I think the advantages of Clojure imo becomes more apparent once you get into exploring and working with data from databases, apis etc. When most things are data, and all libraries are built around the assumption that you’ll be working with data.
I think the keep-index
version by @michael.gaare is on the same level as the python version.
> I think the advantages of Clojure imo becomes more apparent once you get into exploring and working with data from databases, apis etc. When most things are data, and all libraries are built around the assumption that you’ll be working with data.
That's the part I don't quite get yet. I heard so many of people saying things like this on reddit or in the clojure conference videos. Can you give me a concrete example?
This is a good question; I guess I developed my own opinions about this over a period of time so don’t have a good concrete example to hand. I’ve been on a groovy project recently, however, and definitely miss 2 things from Clojure very much: 1 - the fast feedback from an in-process repl (vs compiling and running) and 2 - in idiomatic Clojure you are usually dealing with maps and vectors that can be explored quite easily rather than objects that need to have methods called on and can inherit behaviour and mutate state
I see, it may need to take a while for me to understand why less object/classes would be a benefit, because I don't really get troubled by them in python - most of the time I can inspect the fields of an object like a breeze. i.e. it's just like a map. Regarding the REPL - yeah it's really the killer weapon combined with the s-exp syntax. Python also has a powerful REPL, but I hardly could send code to REPL directly because it's tedious to select the code region in the editor.
How do you feel about mutability/immutability?
Tbh that's also something I'm exploring. Again I see people claim things like "immutability is superior" , but in my years of python dev experience I don't find mutability biting me at all ...
It sounds like you’re pretty happy with python 😄
I think it makes most sense to use a language you feel happy with - perhaps we all get bitten by different things and that affects what we look for
Yeah I am indeed happy with python, I went to clj mainly but I'm trying to write some react-based app and decide to go with CLJS to get some fresh air in the functional programming land
I think there’s a 10 years of Clojure talk where Rich talks about what the kind of programs Clojure was designed for - it’s certainly not for everyone, or for everything
hahah react is a whole other world of things to think about 😄
right, that talk is really great. I watched last week and still remember the graph that shows "domain complexity and misconception" could cost you 10x than choosing whatever language. So true and so verified in my career.
yes!!
it’s quite refreshing to realise that language choice is really a small part of the whole equation, I think as programmers we can get caught up in it sometimes
the language of the system is quite a nice talk in that respect too
yeah, people can build great products with perl or C, which some young programmers treat as "rabbish language"
btw I have posted this question about the power of "everything is data" in reddit https://www.reddit.com/r/Clojure/comments/dfhtcp/about_its_all_data/
np, that’s a good reddit question, well worded & should hopefully get some good responses by people wiser than me 😄
Hey all, new to clojure, coming from node 👋. I am trying to use vscode with some goodies (autocompletion, linting, etc.) and then run that file with repl. On each save, re-run this file. This way I get quick feedback loop and can work in familiar environment instead of in terminal. Does this make sense? If not, what are some alternative methods?
check out #vscode
@UFY00FM0B will do, thanks!
Have you heard of REPL-Driven Development (RDD)? https://github.com/stuarthalloway/presentations/wiki/REPL-Driven-Development
@manutter51 yes, I have, but I would like to read more about this. Being that I have several layers of new (syntax, language, environment, etc.) trying to have some familiarity so I can make progress learning the language
setting up a handy REPL would be of HUGE help and a powerful tool to help you climb the mountain of clojure
ok! and just to make sure i understand what you are saying, this working in the REPL implies that I am writing my code in the terminal, right?
The moment I fell in love with clojure is when I find the power of structural editing combined with real-time eval in REPL
I came from python, python also has an awesome REPL (ipython, which was the inspiration of the famous jupyter notebook). But the thing that really makes Clojure's REPL powerful is you can send the last s-exp to the REPL with one key, due to the sytnax
In Python, do you ever use a REPL to evaluate code inside of a running application? That is something that people sometimes do with Clojure and other (multi-threaded) Lisp systems.
most often for examining state for debugging, less often for modifying the state of the application
There’s a link to a good video on that github page, worth a look if you haven’t seen it before.
I suggest using Calva (since I am maintaining that and since you use vscode) and use it's in-editor REPL for getting quick feedback on your code. So, write code inside (comment ...)
forms and use Calva's commands for evaluating current form and current top level form to examine the results of stuff inside those comment
forms. It's in the Calva README: Something to try first.
Also if you want to get the feel of the repl, you can check out (night-code)[https://sekao.net/nightcode/], but I would just go with calva instead
I love nightcode! It is perfect for a beginner looking to toy around with Clojure. The Insta-REPL feature is awesome and the lack of functionality minimizes distractions with keyboard shortcuts. If nightcode had git functionality, similar to VS Code, and a shortcut to comment out lines of text, I’d probably use it exclusively. Since it doesn’t, I’m using Calva on VS Code for my main text editor.
@here i am having 2 years of experience in clojure & clojurescript, can anyone help me in getting remote work or full time work?
There are #jobs and #remote-jobs channels on Slack where those things are discussed.
@U0CMVHBL2 thanks buddy
http://clojurians.zulipchat.com has a longer history of messages, copied from Slack, for those channels.
I’m putting together a simple use case in a demo web app I’m using to learn clojure. I have a req handler for account registration, when this handler runs I want to insert a new row in the database and then send a welcome email. So far I have this https://gist.github.com/hendore/2d8686fddcec2342688372b300d811e6#file-registration-clj however it’s left me with so many questions, I’m certain there are obvious answers to those that have had more exposure to clojure but I feel a bit lost on where to go next to solve a few things. 1: If the send-welcome-email!
function was implemented and actually sent an email, I wouldn’t want this to happen before returning a response, in other languages I would dispatch an event / add a job to a queue to run later to send the email, what is the clojure way for doing this sort of thing? 2: It’s possible that the insert-account!
function will throw PSQLException
what’s the standard practice for handling this and returning a nicer error back to the request handler function to be given to the user, try/catch maybe? If so where would be the best place to catch the exception and how would I handle that in the request handler to return a nice message? 3: I would like to hash the plain text password before inserting the account, it makes sense for me to do that in insert-account!
should I use something like the threading macro to assoc
or update
password in the account map with a hashed password
(let [account (-> account-info
(select-keys [:name :email :phone :password])
(update :password hash-plaintext-password))]
(…))
4: What about other validation before saving, such as ensuring the password is secure (length, characters, etc...) or making sure name isn’t nil
? I’m sorry about the long post / several questions, I’m just hoping I can learn these little things that I will need to be able to implement other features going forward.There's a lot to unpack there and the answers to most of those questions is "it depends".
just looking for some pointers / links to go do some further investigation more than a step by step, but I understand there’s a lot being asked here 🙈
1. You want send-welcome-email!
to run after successful completion of the registration "work". It doesn't really matter if it happens before the handler returns or not, as long as it happens after successful registration. I would probably have something like
(when success ; whatever that is
(future (send-welcome-email! ,,,)))
so the sending process doesn't hang up the function response (to the user).But you could do it via an agent or a queue or whatever you're used to.
2. Yes, try
/`catch` is the right choice here -- exceptions are idiomatic in Clojure because they are idiomatic in the host language.
As for the try/catch would it be best to place that in the function that could potentially throw the exception insert-account!
and handle it there, maybe return [:error "Email is already in use"]
or would you let that exception bubble up and handle it in the register-account!
or registration-req-handler
functions?
3. looks fine (but you probably want to seed the hash, perhaps with the email or something)
4. There are lots of options for validation. Too complicated for me to type out right now.
No worries, thanks again for your input, you’ve been really helpful the last couple of days I really appreciate the time you’ve taken to help
Re: returning errors -- consider keywords at the lower level (`:ok`, :email-in-use
) and turn them into user-facing strings closer to the user.
It depends 🙂
How much information do you need to convey to callers
You can use keywords, or tuples, or maps, depending on how much information you need to convey back to the caller.