Shortand clojure syntax for properties on hashmaps

One could even go a step further: suggesting design changes to a language that you do not yet fully understand is misguided. Learn how to solve a problem in idiomatic CLJS before trying to inflict upon it a solution that only makes sense in another language. After some time – and learning more about different languages and paradigms – it may turn out you didn’t need what you thought you did. Or, you might learn that you just prefer JavaScript – which is also a fine outcome!

4 Likes

things got a little strange in here. This sounds like a fantastic feature to me. I can’t tell you how many times I’ve done something like

(let [user-info (get-user-info session)
      patient-info (get-patient-info session)]
 (display-patient-info {:user-info user-info
                        :patient-info patient-info}))

I would be very for it. And especially if it made it into core so that the usage was widespread and understood. This seems to get right in line with destructuring like (let [{:keys [foo bar]}]...

1 Like

I assume something is stopping simplification to a map literal? E.g.:

(display-patient-info {:user-info (get-user-info session)
                       :patient-info (get-patient-info session)})

That’s often the direction I end up in.

3 Likes

I agree that is one way to do it. I often don’t go for this more inline style because the sites where work is done are more spread out. A lot of times I like seeing exactly what is going on in one place and then the results. The example given was a trivial example. If that turned into a map with 8 parameters I think my point would be a bit stronger.

For instance here’s an example from our codebase that is creating a handler for a react component. There’s lot of data accumulation and preparation and then the handler is created. These values are used in multiple places and further, it would be difficult to look through all of the maps to see exactly what “work” is being done.

(assoc value
       :send! #(common-actions-send handler {:graph     graph
                                             :phi       phi
                                             :uri-svc   uri-svc
                                             :ribbon    ribbon
                                             :value value
                                             :user-info user-info} %)
  :user-info user-info)
1 Like

That is the kind of repetition I wanted to avoid. This was usually a pain in the ass on javascript, and when the shorthand notation came was a bless. Short after coming to Clojure I noticed the same problem existed here, just that nobody was worried about it.
Glad to see I’m not alone here

That’s the great thing about Clojure - instead of having to wait for syntax changes to the language, you can actually identify pain points you experience and write your own macros to fix them.

Not everyone will experience this same problem, because of different coding styles, but that doesn’t matter because you have the problem, and you can something about it.

I’d advise you to start a personal/company core utility library that you use in all your projects, which contains these types of utilities that address specific problems that you experience while working on various problems. I think I got this idea from Paul Graham in On Lisp.

I think this is also a reason why it is a good thing that it is difficult to get things into core. You can, and should in my opinion, expand on core via your own libraries.

5 Likes

could select-keys satisfy your needs?

(def a {:x 1 :y 2 :z 3})
(def b (select-keys a [:x :y])) ; {:x 1 :y 2}

When I want to get a subset of keys of an object yes absolutely. When I have to build an object from scratch or apply some calculations to certain fields an build a new object not so much.

In any case, thanks for pointing me to something I didn’t know

For applying calculations to fields in a map, you can use update or update-in.

(def m
    {:foo 1
     :bar 2
     :baz 3}

(update m :bar inc)
=>
    {:foo 1
     :bar 3
     :baz 3}

For multiple fields, you can use the threading macro ->

(-> m
    (update :foo dec)
    (update :bar inc)
    (update :baz #(* % %))
=>
    {:foo 0
     :bar 3
     :baz 9}
1 Like

If you don’t like writing update several times, you could also use reduce over a sequence of key/fn pairs:

(reduce
 (fn [m [k f]] (update m k f))
 m
 [[:foo dec]
  [:bar inc]
  [:baz #(* % %)]])

… which, obvs, you could just wrap in a function to which you pass the keys/fns:

(defn update-several [m keys-and-fns]
  (reduce
   (fn [m [k f]] (update m k f))
   m
   keys-and-fns))

(update-several m
                [[:foo dec]
                 [:bar inc]
                 [:baz #(* % %)]])

The same is true for passing a bunch of paths to “modify” a nested data structure using update-in.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.