Fork me on GitHub
#clojure
<
2017-02-13
>
joshjones05:02:23

wanted to share a dumb moment I had, so others who may run across this can recall it. I was using a when-let to pull the first arg from a vector (it was the result of an async alts!!, fwiw):

(when-let [status (first [200 "blah" "blah"])]
  (println "status: " status))    ;; prints status: 200
Of course, when the first element is nil, then the println is not executed:
(when-let [status (first [nil "blah" "blah"])]
  (println "status: " status))  ;; nothing prints, as expected
I thought I'd be clever and destructure the vector:
(when-let [[status] [200 "blah" "blah"]]
  (println "status: " status))  ;; works great, prints status: 200
But when the first element is nil, as in the 2nd example, the println is still executed:
(when-let [[status] [nil "blah" "blah"]]
  (println "status: " status))  ;; prints status: nil
Now, in hindsight, it's clear that this works because [nil] is not nil, so the when-let clause is executed. However, it's a bit tricky due to the destructuring. It's a case where you cannot replace (first ...) with a destructuring. Not rocket science, very obvious, but wasted quite a lot of time on this. It was a bit more difficult to debug due to the vector coming from channels, and thinking that the issue was with my async code, when in face it was with this... Anyway, hope it helps 🙂

oskarth06:02:11

Just recently started using qualified keywords more and I feel like I'm missing something. What's the idiomatic way of qualifying all the key in m (`(def m {:foo "a" :bar 0})`)? If I construct the map directly I can do #:command{:foo "a" :bar 0}) straight away, but if it comes as a variable I can't find a clean solution. Is it just a syntax thing or have I missed a stdlib function?

oskarth06:02:47

Right now I'm hacking around it by doing this horrendous thing:

(->> m
     (map (fn [[k v]] [(keyword "command" (name k)) v]))
     (into {}))

sveri08:02:43

@joshjones The ability to put nil / null into java collections has been a constant soure of pleasure and surprises in Java since it exists 😄

grav10:02:38

Why does clj-time use joda-time not just as an internal format, but at the api-level?

grav10:02:08

Wouldn’t it make more sense to use java’s native format in the api? Currently, we do a lot of conversion back and forth to mitigate this

pesterhazy10:02:12

everyone does

pesterhazy10:02:41

the reason probably is for performance: you only have to convert to and from java.util.Date once

pesterhazy10:02:15

if you have a series of transformations, like now, 2 days before, at midnight, ...

grav11:02:52

Right. Makes sense

grav11:02:42

So maybe a new library that only operates on java.util.Date would make sense?

thheller11:02:52

@grav java.util.Date is really old, java 8 introduced java.time.* which is somewhat like joda-time

grav12:02:04

Okay. Well, the reason we use java.util.Date at all is probably

> (type #inst”2017")
java.util.Date

grav12:02:58

But I guess a tagged literal for java.time.* would solve that

gfredericks12:02:31

you can also override the #inst behavior

pesterhazy12:02:42

I'd rather stick with java.util.Date

pesterhazy12:02:01

which is widely used in libraries

grav12:02:28

That’s what I’m thinking too. I don’t think performance is the issue, more developer experience 🙂

pesterhazy12:02:28

and shuffle back and forth to JodaTime/clj-time when complicated operations are needed

christopherbui13:02:22

Morning. Published this: https://cb.codes/how-to-read-and-debug-clojure-stack-traces/ to try to help alleviate some of the pain points with error messages

rickmoynihan00:02:52

I've been meaning to write something like this to point people at for a while, so thanks for writing this. One other thing I'd say that's often super useful are lines in the stack traces like: at clojure.lang.Compiler.load(Compiler.java:6958) and at clojure.lang.Compiler.eval(Compiler.java:6511) Any lines like this indicate that the function was executing at compile time not runtime, so was likely a file loading (indicated by another stackframe) or an error in macro-expansion or at read-time etc. Knowing whether the error occurs at read time, compile time or runtime is usually one of the first things I look for in a stack trace. Whilst there are definitely a few hard edges in clojure's error messages, if you're experienced at reading them they're really not that bad and can be very informative.

Alex Miller (Clojure team)13:02:23

@gfredericks @pesterhazy in 1.9 there is a protocol for insts and it extends to java.time.Instant if it's available on the classpath

pesterhazy13:02:06

#inst literals will still resolve to java.util.Date I assume?

joshjones13:02:20

in 1.9.0-alpha14, (type #inst “2017”) is java.util.Date fwiw

zane15:02:52

I think I remember someone saying that #inst would evaluate to java.util.Date until Java 7 is no longer supported. 😬

tjtolton15:02:25

Hey, does anyone know where the function lives in Java (or clojure core) that turns clojure symbols into java-ey strings eg: some-class? => SOME_CLASS__QMARK etc

maxfurman15:02:13

which is also exposed as clojure.core/munge. you probably want to use that instead of a java call

tjtolton17:02:14

@val_waeselynck apparently you can just call (munge s) to use that

josh_tackett18:02:50

is there a repl channel were you can test commands?

dpsutton18:02:22

you can write in your own channel or slackbot

josh_tackett18:02:44

is it a slash command?

dpsutton18:02:08

yeah its /clj

josh_tackett18:02:13

nice thank you!

tom19:02:53

Has anyone here worked with buddy and google's certs to unsign a JWT? https://www.googleapis.com/oauth2/v1/certs https://github.com/funcool/buddy-auth

tom19:02:02

Little confused by the multiple certificates google offers, if I'm supposed to attempt unsigning with each or in series or if I need to write them individually to files to use

leov21:02:33

hihi can I add something (build the "materialized views") to the data in atom when it's updated? if I use add-watch, won't it be called twice (actually, repeatedly), if I update the atom in its watch?

tbaldridge21:02:17

yeah, you probably don't want to update an atom from inside that watch's atom

tbaldridge21:02:36

but you can update a different atom and create a dataflow of sorts.

tbaldridge21:02:14

be aware thought that watches are not coordinated so if two threads modify the same atom, the order in which the watches are fired is undefined.

superstructor21:02:58

is the cognitect blog down ?

leov21:02:25

@tbaldridge thanks. so there's no way I stay with one atom?

tbaldridge22:02:27

@leov sure there is, you just add regen-views inside your swap! function everytime update the atom

tbaldridge22:02:43

in other words, regen your views inside the swap function instead of outside