Fork me on GitHub

I want to make a function that's invoked like this:

(build {:builder CfnSubnetGroupProps/builder
        :cache-subnet-group-name "sup"
        :description "sup"
        :subnet-ids ["sup"]})
where it ends up doing this:
(-> (CfnSubnetGroupProps/builder)
    (.cacheSubnetGroupName "sup")
    (.description "sup")
    (.subnetIds ["sup"])
is a macro the right way to go here?


I don't really want to pass the builder object in the map though.


I guess I really want to call something like (CfnSubnetGroupProps/builder {,,,}) except that builder is a 3rd party lib


Looks like a pure function to me that converts a data structure to a series of method calls.


I thought about (doto, but didn't know what benefit that provides over the threading implementation

Lennart Buit05:09:04

Heya, I am having a bit of trouble with making a list of symbols with selective evaluation. So for example, given that thing is :Thing, I want to make a list that looks like (my-symbol (my-other-symbol (my-symbol :Thing))). The following works, but feels overly verbose, is there an easier way?

(let [thing :Thing]
   (list 'my-symbol (list 'my-other-symbol (list 'my-symbol thing))))
=> (my-symbol (my-other-symbol (my-symbol :Thing)))

Lennart Buit05:09:39

I tried this:

(let [thing :Thing]
   '(my-symbol (my-other-symbol (my-symbol ~thing))))
=> (my-symbol (my-other-symbol (my-symbol (clojure.core/unquote thing))))
But that appears to not be the same with that ‘unquote’ in the last pos.


you have to use syntax-quote with backtick ` instead of regular quote

Lennart Buit06:09:53

right, but I don’t want to fqn those symbols (because they don’t exist as def/defns). So this works:

(let [thing :Thing]
  `(~'my-symbol (~'my-other-symbol (~'my-symbol ~thing))))
=> (my-symbol (my-other-symbol (my-symbol :Thing)))


yeah, that's how it works if you need non-namespaced symbols


there's a gensym shorthand my-symbol# which may be useful for you


eg. for local bindings in a macro

Lennart Buit06:09:10

Hmm, that helps when you need fresh names right?


yeah, so that local symbols in a macro won't accidentally shadow outer bindings ('hygeine')

Lennart Buit06:09:46

right, in this case I just need the ‘exact’ symbol. I don’t think it gets evaluated. Thanks for the help!


@lennart.buit A bit ugly but it also does the job:

(read-string (let [thing :Thing] (format "(my-symbol (my-other-symbol (my-symbol %s)))" thing)))
(my-symbol (my-other-symbol (my-symbol :Thing)))
There's a thread about this problem here:


They mention the backtick template macro

Lennart Buit12:09:20

haha great, I was looking for the least ugly solution :’)

Lennart Buit12:09:42

that magic quote thing is cool tho


personally I would go for ~' in that case, but that may also be a sign that you're doing it wrong

Lennart Buit12:09:19

yeah, I had that feeling as well, of ‘trying to do it wrong’

Alex Miller (Clojure team)12:09:38

But you might also look at the largely unused clojure.template which is in core


cool, maybe I could use that to implement macros in sci 🙂

Lennart Buit12:09:47

oh thats used by clojure.test right?

Lennart Buit12:09:58

I think I remember it from the internals of are


oh right, that's where it's used


that seems like the right fit for this kind of problem

Lennart Buit12:09:34

right, I was just going to add this for posterity:

(let [thing :Thing]
  (apply-template '[x] '(my-symbol (my-other-symbol (my-symbol x))) [thing]))
=> (my-symbol (my-other-symbol (my-symbol :Thing)))


user=> (t/apply-template '[x] '(my-symbol (my-other-symbol (my-symbol x))) [:Thing])
(my-symbol (my-other-symbol (my-symbol :Thing)))

Lennart Buit12:09:51

yeah, I was editing my own words by the power of the internet

Lennart Buit12:09:00

thanks for the insights, learned a thing or two today 🙂!


@lennart.buit It seems to be powered by postwalk-replace:

user=> (clojure.walk/postwalk-replace '{_x 10} '(let [x _x] (inc x)))
(let [x 10] (inc x))


and that it turn is just (postwalk (fn [x] (if (contains? smap x) (smap x) x)) form)) I'm in awe of the simplicity of Clojure

Lennart Buit13:09:21

yeah was just about to say, did you mean simple

Lennart Buit13:09:26



both actually


Simple made easy.


I'm the kind of person who first sends an e-mail and then reads it for corrections... so Slack is better for me than IRC 😉

Lennart Buit13:09:42

I think that I edit about 80% of the messages I send

Lennart Buit13:09:56

and I get uneasy when I cannot edit my messages, like email or WhatsApp

Lennart Buit13:09:04

most annoyingly: Wording yourself badly on GitHub, because you can edit things on GH, but not in the emails that are also sent

Lennart Buit13:09:06

I’ll stop with the off-topic


My solution to that is usually delete the original message and post a new one

Lennart Buit13:09:40

words of a serial-editor


hey, this may be something i overlooked or something really stupid i overlooked, but i’m having a problem removing a key from nested maps. could someone give it a look and explain to me why it doesn’t work the way i think it should?

(defn removex [map]
  (let [newmap (dissoc map :x)
        children (:children newmap)]
    (if (some? children)
      (assoc newmap :children (map removex children))


so, say i have

{:a 1 :x 2 :children [{:b 3 :x 4}]}
i’d expect this to remove the :x entry from the toplevel map and overwrite the :children entry with assoc, doing the same thing to every child


thus producing

{:a 1 :children ({:b 3})}


instead i get

{:a 1 :children [{:b 3 :x 4}]}


Using map as a name in clojure is dangerous - you shadow the map function. Use m


oh my fucking god.

😅 4

Because this line (map removex children) is being called with your map, not clojure.core/map


yeah. i needed someone to tell me that option 2 is the one 😞


and maps are ifns too so no error


thanks for pointing out my stupid error


no worries - I’ve done it enough times myself 😄


usually with name

Alex Miller (Clojure team)14:09:39

there are probably some better more generic ways to do this too


most are probably beyond me at this point though 🙂

Alex Miller (Clojure team)14:09:09

like if your goal is to remove all the :x's, you can (defn removex [m] (clojure.walk/postwalk #(if (and (map? %) (contains? % :x)) (dissoc % :x) %) m))

Alex Miller (Clojure team)14:09:57

postwalk will walk the data (bottom-up) and replace each node with the result of the function

Alex Miller (Clojure team)14:09:21

so if you encounter something is a map and has x, remove it. otherwise no change

Alex Miller (Clojure team)14:09:28

the condition and what you do when it's encountered are completely up to the function you write, so this is a very generic technique that is applicable in a wide range of scenarios


wow ok. this looks nice and totally uncomplicated


my first try was looking at specter, but since this was a quick and dirty solution i needed i didin’t get any further than “specter is too complicated for what i need right now”, and neither did i look for purposeful solution in the standard libraries

Alex Miller (Clojure team)14:09:37

you can also do it with specter

Alex Miller (Clojure team)14:09:35

postwalk is unreasonably useful though :) once you think in that way, you see it everywhere


I see there’s more than one walk. what’s the difference between walk, postwalk and prewalk?

Alex Miller (Clojure team)14:09:17

walk is the generic tool. postwalk is bottom up, prewalk is top down. you almost always want postwalk

Alex Miller (Clojure team)14:09:27

postwalk-replace is useful in specific circumstances


oh i see. my CS education is lacking: names come from pre-order / post-order traversal i guess

Alex Miller (Clojure team)15:09:35

those are probably more precise words than bottom-up and top-down :)

Noah Bogart17:09:10

when I call swap! and pass a function that uses remove, the lazy seq is fully realized, right? i don't have to worry about wrapping it in a doall or something?


it's not realized, but any further modification would need to realize it...


if you are doing something side-effecting or resource-dependent in the remove call, you do need to call doall


generally lazy things and side effects / contextual resources are a bad fit


do side effecting things in a swap! is bad too

Noah Bogart17:09:29

this is my current call: (swap! state assoc :events #(remove (fn [event] (same-card? card (:card event))) (:events @state)))

Noah Bogart17:09:34

there aren't any side effects except for the swap! but i'm worried that outdated data might end up in the :events entry


that puts a lambda under a key


remove doesn't even get called

Noah Bogart17:09:10

oh damn, i was thinking of update when i wrote that


even with update, the value under the key would be passed in, you wouldn't deref inside

Noah Bogart17:09:20

removing the anonymous function, should i wrap the remove call in a doall?


yes, if it needs to be coherent

Noah Bogart17:09:43

okay, good to know

Noah Bogart17:09:51

thanks, and sorry for the confusion


something like (swap! state update :events #(doall (remove f %)))


where f is the same as your original


second guessing myself now - doall shouldn't actually be neccessary


doall isn't strictly required, but if you are doing a lot of removes between actual reads of :events which would force the seq, a doall might be a good idea to avoid blowing the stack

👍 4
Noah Bogart17:09:05

yeah, lots of frequent reads, frequent updates/changes


is there any equivalent with clojure 1.10 with: (use ' ?


@papachan is there a feature you need that isn't offered by


I tried raynes/conch but found it easier to use ProcessBuilder / Process directly (they come with the jvm)


In particular " and migrated to".


oh lol it's literally the same code


That all happened as part of the Clojure 1.2 -> 1.3 cycle ("many years ago").