Fork me on GitHub

Any recorded link to that Eric Normand + Yehonathan Sharvit talk that was supposed to happen on 3rd?


Hi, is it possible to use something like JMX Exporter in a repl to have some insight into metrics? Does this even make sense for a repl process? I’m just looking to learn a bit more about the JVM and would like to have a look how different operations affect things like GC etc.


I haven't used JMX Explorer in particular, but it should be possible. I've used VisualVM and other profiling tools to help tune memory usage and performance. (Everything in this vein I've learned from

M J15:11:31

how do I get index of an object, where id=:id ? For example, a r/atom that the end result is: [{:id 2014, :ticked true} {:id 1479, :ticked true} {:id 1490, :ticked true} {:id 0b4d9caf-4c0b-41b6-8fca-46e63915c427, :ticked true} {:id 1993, :ticked true}]


(first (keep-indexed #(when (= id (:id %2)) %1) d))

M J15:11:09

(reset! array-of-ticked (update @array-of-ticked index (fn [e] (assoc e :ticked %)))) This is what I do currently, update by index. I wanna update by :id. How exactly?


i do not understand your question/code

M J16:11:20

I want to reset array-of-ticked, make :ticked be true, where :id = 1993 for example


(map #(if (= 1993 (:id %)) (assoc % :ticked true) %) @array-of-ticked)


Rather than storing the data in an array (and updating by index), I would store the data in a hash map indexed by id. That would make modifying the data structure much simpler. It would look like:

(swap! ticked update-in [id :ticked] not)


yeah i would do the same.

M J07:11:21

Ok, so after switiching to hash-map, how exactly do I write it? This is what I had before since its a reagent:

(reset! array-of-ticked (update @array-of-ticked index (fn [e]                                                                                                                                              (assoc e :ticked %))))


Rather than your atom being an array, it could be a hash-map like below. You could update it using swap!. Here's some examples of what the atom would be:

(def ticked {})
@ticked ;; {}

(swap! ticked update 1993 not)
@ticked ;; {1993 true}

(swap! ticked update 1993 not)
@ticked ;; {1993 false}

(swap! ticked update 1541 not)
@ticked ;; {1993 false 1541 true}
Let me know if you have any questions!


There is no core function to flip the vals and the keys of a map is there?


lol I just wrote

(defn swap-map [m] (reduce-kv (fn [m k v] (assoc m v k)) {} m))
and thought I am cool


There is 0 shame (and perhaps some reason for pride) to reimplement functions in Clojure core 🙂

clojure-spin 1

I looked at the map-invert source code, and it's essentially the same as Benjamin's version, but uses persistent! and transient. What's up with that?

Alex Miller (Clojure team)22:11:40

The whole point of transients is to improve performance when bulk loading a collection

❤️ 2
Alex Miller (Clojure team)00:11:26

Functions like into or reduce are doing that for you so usually you’re getting that without knowing it


Hi all, I'm offering free ad-hoc 1:1 Clojure mentoring for the next few weeks (as part of an experiment to create a new type of help resource for the community). Looking for other mentors to join in too. See details here:

💯 3

I don't want to hijack the clojureverse discussion, but I want to say that this is really generous of you! And this might actually be a way to collectively help with clojure adoption.


Thanks @U3X7174KS. TBD if it anybody bites.

🤞 1

So as a beginner Clojurian and a seasoned web developer I have a question about Clojure's philosophy on macros. Homoiconicity is presented as one of the most elegant and powerful features of the language, and also presented as one of the most dangerous features of the language. I can see both sides -- the capacity for the language to interpret itself allows for a lot of flexibility even down to the syntax, but this very flexibility also seems to mean that each clojure program potentially uses its own flavor of the language, which could be confusing to those who are new to the codebase. As someone who has started learning the language but not experimented with macros are there best practices or a practical philosophy or advice that I can adhere to regarding the use of macros?

👍 1

I think you've got a good perspective on the double-edged sword of macros. My philosophy is: "don't use macros unless you must use macros". In practice, I've rarely had to write macros within an application (4 times in 10 years?), and mostly have written macros for sugaring the APIs of some library-like things. As a beginner Clojurian, I wouldn't even worry about writing macros at all. Being able to recognize and use special forms / macros in the standard library and other libraries is sufficient for a long time.


@U0CLNM0N6 this sort of confirms my instincts -- it's nifty but maybe dangerous and the standard library is extremely powerful. Maybe I'll leave metaprogramming alone for the time being.


Macros are nifty and powerful, and I'm very glad they're in the language (to allow for libraries like clojure.async), but, not necessary for most day-to-day needs. IMO, they definitely don't need to be on a beginners "must learn" list.


Totally agree with the other comments. Despite being fairly inexperienced with clojure, I have used macros a few times to improve code clarity. One that springs to mind is a macro to execute the body in a try catch, log any error that occurs and return nil. It was cropping up multiple times in the problem I was solving and it reduced some visual clutter from the code. It wasn’t a production codebase and there could have been (probably were) better ways to solve the problem, but it helped me at the time and I think it’s okay to dip your toe in the water just to get a feel for it

Alex Miller (Clojure team)19:11:52

I would not say they are dangerous. But I think a fair philosophy of preference is: data >> function >> macro and these are not mutually exclusive

Alex Miller (Clojure team)19:11:12

if you can represent your problem as data and use the standard api of data manipulation to solve it, that is always a good base. if you need functions that give you better tools to manipulate that data, do so. if you then want custom language, then by all means - that's what macros are for (but you still probably want to have those macros assemble function calls that transform data)

Alex Miller (Clojure team)19:11:00

reach for macros when you want a custom language to talk about your problem, or a refinement of existing macros (for control flow in particular), or for advanced forms of DRY

👍 2

The most annoying issue to run into with macros is basically custom versions of def. People write macros that do some kind of cool neat thing, make the macro also def a global name

plus_one 1

In your learning journey I'm sure you'll come across clojure spec ( Contrasting that library whose user-facing API is all macros, with malli ( whose use-facing API is all data and functions should help solidify the tradeoffs between the two. For example let's say you have a spec describing a hashmap that must contain a certain set of keys. If you want to define a new spec based on that spec (like adding a new required key) you must do some really annoying things because you're dealing with a macro. To do the same thing with malli you can use conj because you're dealing with data.


@U051V5LLP Which is why supports full programmatic construction of Specs (and even has specs-as-data as a layer in there)...


(it just isn't "cooked" yet)

Young-il Choo21:11:37

My two cents on when to use macros: you need to delay the evaluation of some expression. Examples: all the control structures (if, let, etc.), with-open (and other with-*).


There is also a continuum between other code generation approaches and macros and homoiconicity makes all of them easier. It is easy to generate clojure code and spit it to a file because it is all clojure data structures and clojure.core provides all kinds of functions for manipulating those


Clojure being a Lisp-1, macros are not as big a deal as in Common Lisp, because macros hide boilerplate and Lisp-1 eliminates the boilerplate of using anonymous functions. That said, macros are neither dangerous nor to be avoided until some point in time/experience with Clojure; use them to hide boilerplate. Lisps are intoxicating; you may be inventing a new Web DSL in a few days and want macros badly. As for macros confusing codebases, HLL mechanisms do not generate confusion, they magnify their users' confusion, commensurately with the mechanism power. But we Lisp for power. Good programmers can safely embrace more powerful did I segue into dragging Java? :rolling_on_the_floor_laughing:

Will Weiss21:11:35

Hi! I'm learning Datomic and enjoying the Max Datom tutorial, but am struggling with I'm wanting to use :xform but am being told that the provided function needs to be listed under :xforms. Adding ns/ does not seem to work. Reading I'm not sure I can add to the :xforms . Any idea how to proceed? Thanks in advance!

(ns level-12
    [datomic.client.api :as d]
    [max-datom.connections :refer [db]]))

(defn comment-count-str [x]
  (str "Comment Count: " (count x)))

(d/q '[:find  
         (pull ?posts [[:post/comments :xform comment-count-str]])
       :where [?posts :post/author _]] db)
clojure.lang.ExceptionInfo: 'comment-count-str' needs to be listed under :xforms in datomic/ion-config.edn {:cognitect.anomalies/category :cognitect.anomalies/forbidden, :cognitect.anomalies/message "'comment-count-str' needs to be listed under :xforms in datomic/ion-config.edn"}


The function name needs to be fully qualified, ie. level-12/comment-count-str (they've whitelisted it for you already).

🙌 1
Will Weiss22:11:48

Aha! Now I see how the namespaces are declared and used — thanks so much!

👍 1