This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-11-09
Channels
- # aleph (1)
- # announcements (7)
- # asami (1)
- # beginners (44)
- # calva (54)
- # cherry (24)
- # cider (6)
- # clj-kondo (19)
- # cljsrn (27)
- # clojure (119)
- # clojure-europe (61)
- # clojure-gamedev (38)
- # clojure-germany (7)
- # clojure-nl (1)
- # clojure-norway (104)
- # clojure-portugal (4)
- # clojure-spec (4)
- # clojure-uk (1)
- # clojurescript (38)
- # cursive (18)
- # datomic (11)
- # emacs (9)
- # events (1)
- # fulcro (4)
- # holy-lambda (7)
- # introduce-yourself (7)
- # jobs (1)
- # malli (6)
- # off-topic (4)
- # pathom (4)
- # pedestal (16)
- # podcasts-discuss (1)
- # polylith (27)
- # portal (17)
- # releases (2)
- # shadow-cljs (46)
- # squint (1)
- # xtdb (9)
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 http://clojure-goes-fast.com/blog/)
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}]
(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?
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)
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!https://clojure.github.io/clojure/clojure.set-api.html#clojure.set/map-invert
lol I just wrote
(defn swap-map [m] (reduce-kv (fn [m k v] (assoc m v k)) {} m))
and thought I am coolThere is 0 shame (and perhaps some reason for pride) to reimplement functions in Clojure core 🙂
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?
It’s faster
The whole point of transients is to improve performance when bulk loading a collection
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: https://clojureverse.org/t/1-1-ad-hoc-mentoring/9500
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.
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?
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
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
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)
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
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
In your learning journey I'm sure you'll come across clojure spec (https://clojure.org/guides/spec).
Contrasting that library whose user-facing API is all macros, with malli (https://github.com/metosin/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 https://github.com/clojure/spec-alpha2 supports full programmatic construction of Specs (and even has specs-as-data as a layer in there)...
(it just isn't "cooked" yet)
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 mechanisms...how did I segue into dragging Java? :rolling_on_the_floor_laughing:
Hi! I'm learning Datomic and enjoying the Max Datom tutorial, but am struggling with https://max-datom.com/#/4EC4A43A-698E-4240-9E5E-9A9C36C93673. 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 https://docs.datomic.com/on-prem/query/pull.html#xform I'm not sure I can add to the :xforms
.
Any idea how to proceed? Thanks in advance!
(ns level-12
(:require
[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"}