Fork me on GitHub

Is the special {} and [] syntax created through reader macros? Or something else?


very dope, so clean. It really just is macros all the way down 😄


To be precise, the macros in the reader are not the same as the macros you can define with defmacro. You cannot define your own reader macros in Clojure source code. You can only add new syntax like {} or [] i Clojure on the JVM by changing the Java source code for Clojure's reader.


Can anybody point me to a good date/time library that works on clojure and clojurescript?

delaguardo14:06:48 Tick is another one which uses first one to make high level abstractions


Heya! Thanks for having me here. I have managed to complete a coding challenge using Clojure in Emacs w/ Cider. The code runs. I turned on the LSP at the end just to see what it would do with docstrings and it has decided to lint my structs as "unresolved-symbols". Should I stay confident in my code here, or does the LSP know something I don't yet appreciate? I'm new to Clojure/Java.


It's linting on both the definition and anywhere they are referenced:

(ns tutorial.dealership)

(defstruct car :model :cost)
(defstruct customer :name :budget :coupon)
(defstruct coupon :type :code :discount)

(def cars [(struct car "BMW" 60000)
           (struct car "Ferrari" 100000)
           (struct car "Fiat" 20000)])

(def coupons [(struct-map coupon :type 'percent :code "GIMMIE20" :discount 20)
              (struct-map coupon :type 'fixed :code "THAT5K" :discount 5000)])


@trev did the coding challenge say to use defstruct?


to answer your direct question: the LSP implementation doesn't know about structs apparently

🙌 1
👍 1

Haha...Hm. The course focused on defstruct as a means to create structured data, then gave me the challenge to use whatever tools were already taught


So, in a round-about way, yes


just use plain maps or records if you must. The course is wrong.


Welp, it was $15. I can get over that


Hopefully there aren't too many deprecated concepts


I'm curious to know what course that is (so we can help others avoid it)...


if anything, a linter/LSP should warn: "don't use defstruct"


Sounds good to me, actually, if the var has deprecated metadata, clj-kondo/clojure-lsp will already warn about it right?


it doesn't have the deprecated metadata


it just shouldn't be used 🙂

😂 1

^{:deprecated "Just don't use it, please"}


> just use plain maps or records if you must. The course is wrong. @ghadi I was thinking about composition from the data source, and wondering what that data may look like if it came from some other resource. It structs have that nice shorthand (:key struct) rather than (get map :key). Is it more advantageous to avoid the abstraction of records?


all maps support the (:keyword access)

👍 1



That course has come up here before -- look at the 1 * reviews and you'll see at least one mention of this Slack and feedback on the poor practices in that course.


There weren't many choices

Stef Coetzee17:06:12

Have you taken a look at @U050P0ACR's courses? I'm working through his API course and learning a great deal. :)


Oh man, Eric is how I got here. I was cleaning my car and looking for programming podcasts on AntennaPod, and he came up. I started from Episode 1.


I wanted to gently dip my toes in, so I grabbed the $15 Udemy sale before deciding that I needed to pay the $600 that I am sure his courses are worth


Got what I paid for, clearly

Stef Coetzee17:06:17

Daniel Higginbotham's book (which can be read freely on his website if you'd like to try before you buy) is also a decent intro. Good luck and keep at it! 🙌😁

👍 1

Thank you


records have a further compiler optimization that specializes access on the record's declared fields My suggestion is: start with maps, hug your maps, use maps as long as possible


defrecords subsume the old defstruct because records can implement protocols & interfaces, as well as do all the things that structs do


It was supposedly updated in 2022...which was part of my purchasing decision. I see that the update is probably meaningless


@ghadi I suppose it's fair to say that records enforce the shape of an expected model more readily?


If maps have less overhead, I'd rather do that and expect bad input


none of these mentioned mechanisms "prevent" invalid data


I noticed that. With the record, however, if I omitted the :coupon key, I got an error on implementing the new record, as apposed to some mishap down the line where accessing that key fails.


Potato potato

Ian Oliveira16:06:29

Hi Folks, is there a way to know the caller of a function? like something bellow

(defn print-my-caller[]
  (print *caller*))

(defn my-function []



if you want this just for debugging you can look at stack traces. clojure.repl/pst (print stack trace) is a handy way to accomplish this


licenses=> (defn foo []
             (pst (ex-info "hi" {}) 4)
licenses=> (defn bar [] (foo))
licenses=> (defn quux [] (bar))
licenses=> (quux)
ExceptionInfo hi {}
	build.licenses/foo (NO_SOURCE_FILE:217)
	build.licenses/foo (NO_SOURCE_FILE:216)
	build.licenses/bar (NO_SOURCE_FILE:219)
	build.licenses/bar (NO_SOURCE_FILE:219)


here i have a function quux which calls bar which calls foo. And that prints a stacktrace of 4 levels. (just ballparking with 4. adjust as desired)

Ian Oliveira16:06:05

(defn get-customer-by-id [customer-id]
  (db/query "SELECT ... where customer-id =" customer-id)) ; example code
Imagine that db/query function executes the query and than exports the time spend to execute the query to prometheus.. and we want to add to this metric the "query name" which in this case is get-customer-id and in this case is the name of the caller of db/query


oh no this is not a good solution for that


for human consumption?


guys I have a mega beginners questions. I’m sorry in advance for having to ask but I tried googling and I probably can’t even formulated the question correctly:( I am trying to build a list of data structure from smaller structures that I save in variables using def before hand. At the end I basically need a list of maps but the maps are big in themselves so I’m trying to split it up in smaller chunks. The way I figured it out to work as I need it to is like this:

mud.interface> (def one {:name "one"})
mud.interface> (def two {:name "two"})
mud.interface> (list one two)
({:name "one"} {:name "two"})
Is there a better/more canonical way of achieving this or is this the way to do it?


I think the more idiomatic thing here would be to use a vector literal: [one two]


Despite being a lisp, lists tend to be the exception as oppose to the rule in Clojure


thank you that’s good insight. So I should try and use a vector if my usecase doesn’t call for a list then. 🙇


how are you building the maps?


I just use

(def map-name {...})
And then there’s stuff in the map like other maps or vectors


is it all constant/literals? or are you pulling data from some source?


I am using these maps as the data source actually. Like a sort of confing file. Most of the contents is literals but I sprinkle some function names here and there


it is somewhat uncommon to see a big map def'ed, if it is all constants/literals you might treat it as a data, and load it at runtime using read (avoiding passing it through the compiler), this type of thing is common for configuration files


because I have function refs in there is why I was thinking of treating them like clj files instead of an external data source. I’m very early in my thinking so I might end up just reading from files


Defining your data as EDN might be what you want. You can define symbols in EDN, which I think would let you reference function names in your data, without having to define everything in clj files


I’ll look EDN up thank you I don’t know what that is:D


edn is a system for the conveyance of values. It is not a type system, and has no schemas. Nor is it a system for representing objects - there are no reference types
so I would need a mechanism to convert a literal value into a function ref?


I think symbols would do the trick, but honestly I haven't tired this myself 🙂


I think by reference types, the spec is referring to referencing other things within the EDN file itself. That said, I believe I've seen libraries define their own reference types using custom tagged elements

🙏 1

> I have managed to complete a coding challenge using Clojure in Emacs w/ Cider. Refactored with @ghadi's suggestions in mind. Here's the exercise: A "car dealership" and coupon system. The specifics of what was supposed to be accomplished were pretty simple. I added some layers of complexity, such as variable coupon candidates. I also tried to keep my functions as simple as possible, with one param in, simple return value out.


rapid fire: list-affordable-cars is Doing Too Much™. It's applying all the discounts, and comparing it to a customer's budget. Separate those concerns: map applying the discounts, filter by budget cars and coupons should be parameters to the functions that want them. I realize this is a learning exercise. It's ok to have them as top level defs, but then explicitly pass those collections to functions, don't just reach for top-level defs from inside your functions.

💥 1
🧵 1

Just to be clear on the objective here: At no point do I ever want to reach for the namespace scope for either cars or coupons. They should be passed into a function from within that scope, and calculated/acted-upon from there?


A function such as a main or init function?


Lighting Round Challenge:


hate to say it but no

💥 1

the internal calls to (get-vehicles) are still global state, not parameters


just pass the vehicles and coupons to present-options -- meaning more arguments


if different parts of your application want to call these functions with different cars and coupons, they cannot because you have globals not parameters


That's easy feedback to fix. I was trying to stick to one argument per function but perhaps in the context of an action such as present-options this is going too far


In terms of separating concerns, are we good?


@ghadi Another try.


'percent quoting symbols is not idiomatic clojure, more like common-lisp

🧵 1

use :percent or :fixed

Allan Gonçalves17:06:32

for this specific case, using case instead of cond feels more idiomatic to me


> 'percent quoting symbols is not idiomatic clojure Ah, they were exampled in the course-we-did-already-name. I recognized them from elisp, which is kinda wanting to be like CL. I see them as easier to grok vs :type :percent Is there another practical reason for wanting to use the colon?


Challenge accepted


You access coupons by their code but keep them in a list. Rather than inspecting each coupon one-by-one looking for the code, just store them by code in a map of code -> coupon


I suppose if the key of the coupon map is a string, that could be easy. In terms of memory, is it better to intern it as a symbol so I can :THAT5K -> coupon?


I can never tell if I'm splitting hairs


:THAT5K is a keyword, not a symbol You should not use keywords for high cardinality sets of values


TIL what cardinality is


if you were doing a production system, you'd want an efficient way to check whether a coupon is valid, without scanning the whole list. But the list is gonna be your canonical source probably


That's exactly how I imagine it. Unless it's from a document database, or reformatted after being retrieved.


Though I suppose you would SQL query where (= :code "STRING")


I am used to clunky data formatting from places like Shopify


(transduce (map #((juxt :x :y) %))
    (fn [r n]
      (reduce + r n)))
  [{:x 1 :y 2}
   {:x 1 :y 4}]
Is there a shorter way to write this as a transducer? Basically trying to pick some vals from a bunch of maps by key and sum them.

Alex Miller (Clojure team)18:06:32

(transduce (mapcat (juxt :x :y)) + 0 [{:x 1 :y 2} {:x 1 :y 4}])

gratitude-thank-you 1

how to check empty condition for clojure.lang.PersistentList ?


that isn't a list that is a long


sorry updated the question!, I tried (empty? v) which gave me the issue , when I printed type it says it is clojure.lang.PersistentList


then somtimes v is a list and sometimes it is a long


if empty? throws that exception it means it was passed a long


user=> (empty? 1)
Execution error (IllegalArgumentException) at user/eval173 (REPL:1).
Don't know how to create ISeq from: java.lang.Long


ahhh I see? I am trying to write a condition for emty check! how to check if the collection is empty? which passes for strings and numbers


(and (coll? v) (empty? v))


(although keep in mind coll? returns false for nil, which often gets treated as an empty collection in clojure)


super cool thanks you 🙂