Fork me on GitHub
#beginners
<
2021-04-30
>
Eddie01:04:02

I’m failing to find a documented example of a return type-hint + a docstring on a function. The compiler tells me this is wrong:

(defn foo ^Long
  "I do nothing" 
  [^Long x] x)

;; Syntax error: Metadata can only be applied to IMetas
It compiles if the type hint is moved after the docstring, but I’m not sure if that is annotating the correct thing. Any advice for dong this right?

Alex Miller (Clojure team)01:04:51

That’s correct - it goes before the arg vector

🙏 4
Eddie01:04:24

Gotcha. Thanks @alexmiller!

Michael Lan02:04:35

where’s the log for this slack?

seancorfield03:04:34

The former is purely a readonly searchable index/log. The latter is also a chat community, that has a one-way mirror of nearly all channels here and is searchable with no limits (because it is on Zulip’s free open source plan).

Mattias08:04:27

Whoa. Nice. For some reason I earlier just assumed information was gone, unless I captured it somehow. Didn’t occur to me someone was saving things. Things I learn. 🙂

seancorfield17:04:57

@UCW3QKWKT look for either @U055W814A and/or @UFNE73UF4 in a channel. If they’re there, messages are being saved. If not, you can /invite them to a channel and new messages from that point will get saved.

Edward Ciafardini03:04:55

Going through the Reagent documentation and an example is provided for updating state using "on-change" for an input.

(ns example
  (:require [reagent.core :as r]))
(defn atom-input [value]
  [:input {:type "text"
           :value @value
           :on-change #(reset! value (-> % .-target .-value))}])

(defn shared-state []
  (let [val (r/atom "foo")]
    (fn []
      [:div
       [:p "The value is now: " @val]
       [:p "Change it here: " [atom-input val]]])))
This mostly makes sense to me, but I am struggling picking apart this specific line:
:on-change #(reset! value (-> % .-target .-value))}])
Searching the web for "->" and ".-" has not yielded great results as you might imagine

seancorfield03:04:33

.-foo is a JavaScript field selection in ClojureScript. -> is the “thread first” macro.

👍 4
seancorfield03:04:17

(-> % .-target .-value) will macroexpand to (.-value (.-target %)) if that helps: get the target field from the anonymous function’s argument, and then get the value field from that.

seancorfield03:04:44

(you may also find the #reagent channel helpful, if you’re not already a member)

valerauko09:04:57

I made a namespace that should generate a java class with (:gen-class This worked all right until I made an edit to the namespace in question. Since then (even if I revert the changes to the code that worked earlier) lein just refuses to aot it anymore, giving me java.lang.ClassNotFoundException What can cause this?

valerauko09:04:29

I've tried the "usual" candidates like clearing target and even wiping my .m2

valerauko09:04:10

Even if I explicitly try to run lein compile app.class-namespace

valerauko09:04:00

Hmm it finally re-compiled it once I removed every reference to the class from other places in the source first

Juλian (he/him)10:04:16

is there a way to test side-effects of functions, for example the output of println? or should I make the function return the string instead of printing and call println with on the result of the function?

delaguardo10:04:28

(with-out-str (fn-with-side-effects)) ;; => "printed string"

delaguardo10:04:46

but I would try to avoid side effects as much as I can. so return a string to be printed sound right for me

Juλian (he/him)10:04:14

it's a text based game, so printing is an essential part of it 😅

Juλian (he/him)10:04:27

but thanks for the answer

delaguardo10:04:21

I don’t meant to say “avoid it completely” ) I should say “keep it as far from core functionality as possible”.

Juλian (he/him)11:04:41

just had a thought during my lunch run.. maybe I want to reuse the code for a different interface, for example a webpage. that would be easier then, too. thanks for the hint

dvingo15:04:14

it is often recommended in designing clojure programs to have a pure core and then a "runner" that performs the side effects. There are some really great talks about this: https://www.youtube.com/watch?v=ZQkIWWTygio https://www.youtube.com/watch?v=JvGXyNXky0Q see also, re-frame's dispatch

pithyless16:04:17

I think this talk was also pretty good about strategies on how to pull apart effects from the rest of your codebase: https://www.youtube.com/watch?v=IZlt6hH8YiA

Krishan V13:04:49

Hey everyone, I am looking to dissoc some keys from a list of maps. How do I go about passing the current iteration of a map function to a dissoc?

(def final-map (map (dissoc <I need the current iteration here>[:uselessKey1 :uselessKey2]) (vals items)]))

manutter5113:04:41

You want an anonymous function there: (def final-map (map #(dissoc % :uselessKey1 :uselessKey2) (vals items)]))

🙌 4
Krishan V14:04:32

What is the significance of # in this context? I see this a lot in Clojure but can't find a doc for this. What is the terminology?

manutter5114:04:58

That’s one of the two ways of writing an anonymous function. It’s basically just a shorthand way to throw together a quick anonymous function for use with things like map and filter and reduce and so on.

manutter5114:04:13

The % means the first arg to the function, and if you have more args than that, the second arg is %2 and the third is %3 and so on.

manutter5113:04:05

(Also no square brackets around the keys you want to dissoc from the map)

Prabu Rajan16:04:22

Hi, which of the following for this is a better option? Are there any better than these?

;; option 1
(defn update-user [users id user]
  (update-in users [id]
             #(if (nil? %)
                (throw (IllegalArgumentException. (str "User " id " does not exist")))
                user)))

;; option 2
(defn update-user-contains [users id user]
  (if (contains? users id)
    (assoc-in users [id] user)
    (throw (IllegalArgumentException. (str "User " id " does not exist")))))

(update-user
 {:one {::first-name "Agatha" ::last-name "Christie" ::email ""}}
 :two
 {::first-name "Prabu"
  ::last-name "Rajan"
  ::email ""})

delaguardo17:04:04

Second will have nicer stacktrace

Prabu Rajan17:04:26

I agree. I prefer the 2nd one too in terms of simplicity. I was just wondering in terms of performance, which one would be better, but it turns out that both take almost similar time, but I have not really measured it for large maps

Franco Gasperino18:04:57

what is the preferred idiom of using a defn- vs a letfn. I understand the scope, but asking for style

Alex Miller (Clojure team)18:04:31

In general, I think top-level functions should be defn-

Alex Miller (Clojure team)18:04:48

letfn is mostly useful inside functions, particularly when making something recursive

Alex Miller (Clojure team)18:04:02

kind of for "functions private to a function"

Alex Miller (Clojure team)18:04:23

but generally even for things like that, I mostly just make defn- as they are easier to test, doc, etc

Noah Bogart18:04:30

letfn is also good for closing over local variables without having to pass them in

Franco Gasperino18:04:11

both of those answers are appreciated

Old account19:04:25

Hi, what are Clojure editor usage statistics?

dpsutton19:04:12

second graph in that section

dpsutton19:04:02

note this is not a true editor usage statistics but editor usage statistics of people who responded to the state of clojure survey. Hopefully it is representative of the community at large but that's not a certainty

Alex Miller (Clojure team)19:04:55

it's ~2500 responses so probably a good enough sample (tracks with prior years)

piyer19:04:23

Looking to find the clojure docker image to run in production. I found https://github.com/Quantisan/docker-clojure/blob/99e09867b734efda57f117a1a266bcb2dce25a33/target/openjdk-11-buster/lein/Dockerfile, is there a tag without lein? or what is the recommended version?

ghadi19:04:53

@munichlinux my standard procedure is to build a jar then put it in a plain JDK container

ghadi19:04:14

I never ship lein to prod

piyer19:04:32

that is what I was expecting to do.

ghadi19:04:02

clojure is "just a library"

ghadi19:04:15

my prod containers call java -cp the.jar clojure.main -m my.entrypoint.namespace as entrypoint

piyer19:04:27

I thought there is some version with just jdk 11. I guess I should look in the openjdk docker.

ghadi19:04:56

adoptopenjdk or corretto are my goto containers

ghadi19:04:15

fyi alpine isn't "official" until after 11

ghadi19:04:32

(I think, JDK 14 gave real support for it?)

ghadi19:04:55

everyone uses it, but YMMV

ghadi19:04:29

right -- the JDK didn't officially support Alpine in 8 or 11

ghadi19:04:25

some people still put together artifacts for alpine -- just not supported

piyer19:04:08

I see, what would you recommend?

piyer19:04:21

I also see debian.

ghadi20:04:34

the debian based one is fine

ghadi20:04:42

if you want alpine you should use latest (16)

piyer20:04:16

ya, clojure LTS says it supports 11.

ghadi20:04:16

and look into jlink , which is a better way of stripping down a JVM for smaller artifact sizes