Generally good suggestion, although I can not agree with "avoid high-order functions"
Yes same here. I actually think his example using comp
looks more readable than the one using anonymous functions
My thoughts exactly
Agree here. I use comp
more and more often instead of nested anonymous function. Especially when I need argument function for filter
, remove
, sort-by
, juxt
, etc
comp
can be used to convert deeply nested function calls to a concatenation of self-contained functions. The other way to makes it easier to read is to use threading macro at the first position, but it still looks weird to me.
For example, I would rather prefer comp
here
(->> {1 {:id 1 :product {:name "Macbook Retina"}}}
(map (juxt key (comp #(str/replace % " " "-") str/lower-case :name :product val)))
(into {}))
; => {1 "macbook-retina"}
more than
#(str/replace (str/lower-case (:name (:product (val %)))) " " "-")
or
#(-> % val :product :name str/lower-case (str/replace " " "-"))
threading macro approach would get a bit messier when we need to mix ->
and ->>
I would probably create a function extracted-name
or something like that which would use the threading macro
and the map would just call the function š
Yesss. Self documenting code for the win š
Thatās an option but I think itās not always. I find myself less strict with descriptive name when I have pure functions and repl. I try not to overly create a new functions these days. Itās easy to run/play with a piece of code than dealing with naming confusion and conflicts to me š
Do you usually write code in the repl and then move it over to your source files, or type it first in the source files and then evaluate in the repl?
The later
If you wrap #(-> % val :product :name str/lower-case (str/replace " " "-"))
in a function, you wonāt reuse it very often anyway because it tights to structure of the input map.
I might group str/lower-case
and (str/replace " " "-")
together but not with the others
I believe you probably donāt want something like (defn access-name-in-map [m] (-> m val :product :name))
as well
I believe itās same problem Rich said about Class and how you have to create a lot of duplicated methods to work with specificity of types
for me the tradeoff is still worth it when I look at:
(->> {1 {:id 1 :product {:name "Macbook Retina"}}}
(map (juxt key (comp #(str/replace % " " "-") str/lower-case :name :product val)))
(into {}))
I have no idea what itās doingā¦
this I can read and understand:
(->> {1 {:id 1 :product {:name "Macbook Retina"}}}
(map product->name-in-param-case)
(into {}))
Yeah, I agree that that one is begging to be pulled out
or at least use an anon fn in the form (fn [[k v]] ...)
I love map juxt combined with into {}
, but sometimes you can push it too far
then again, I do kinda hate the #()
anon fn form, so it could just be me
This is my personally opinion.
For product->name-in-param-case
, I have to jump to the source code to find out what it does. It might even have a surprise like side-effects inside. In many cases you need it, but not always.
But for (comp to-slug :name :product val)
, I know it at a glance and fully understand what it does. And I believe itās familiarizable.
I think benefit of ability to see and understand more things in a single screen is not rated enough
However, I completely understand you all points. I definitely can see myself had the same opinion as you in the past. Just to give a different perspective.
tap: in the case you mix ->
and ->>
you can use as->
Yeah, sure but probably not in an anonymous function, right?
(comp to-slug :name :product val)
is fine with me
itās once you start having to stick extra anonymous functions into the comp that I start thinking twice
yeah, thatās fair
true
occasionally Iāll use (comp (partial xx yy) ā¦)
, I find that usually reads cleaner than additional anonymous functions
In that blog post, I also donāt fully agree with āDonāt rely on implicit nil-to-false coercionā.
I think function like keep
which operates on nil-to-false coercion is quite handy https://clojuredocs.org/clojure.core/keep
@tap: after reading Clean Code, I actually agreed with the author that I donāt have to understand all the details when Iām reading through the code only if Iām interested in the details of implementation, I would go and check that after applying this rule more and more, our codebase became much nicer to read for others it makes sense for you now to have all the details in one place, but it will be hard for others and your future yourself š thatās my opinion š
Love keep
keep is nice, never used it
@andrut I really really like Clean Code. Itās my first favorite programming book. And I do follow what the author said for years, religiously in some period of my career.
It all comes down to finding a balance between verbosity and clarity. And I think Clojure gives us a possibility for different balance from static-typed OO language.
Iām not advocate for doing code golf here, but if we can get a short code with clarity, why not? (comp to-slug :name :product val)
have almost the same number of character as product->name-in-param-case
I donāt expect a person who donāt familiar with comp
to understand this, but I believe anyone who familiar with it will understand this statement at a glance like me. I believe we should try to utilize more what clojure provides. If anyone donāt understand the statement, go play with it in your repl. I believe it wouldnāt take more than a few times, youāll feel that itās natural.
I do have somewhat similar problem with assoc
when I started using clojure. I came from a place where we use put
or add
to put thing into a collection. And maybe because Iām not coming from native-English speaking country, the word āassociationā didnāt ring that meaning to me. Itās not a word that I use often everyday. But I stick with it and one day it became natural.
If I were to write code optimizing for myself who not familiar with assoc
to read, Iāll have to alias it to something like immutable-put
(def immutable-put assoc)
I believe everyone here would agree that I should not do that.I agree
(comp to-slug :name :product val)
looks legit š
(juxt key (comp #(str/replace % " " "-") str/lower-case :name :product val))
doesnāt
what about (juxt key (comp to-slug :name :product val))
?
arguable, too much of mental overhead for me, but maybe Iām stupid š
Nah, donāt go that way. I believe itās just a familiarity. Again, totally understand you. Just trying to give an argument supporting my trade-off view. If we all agree with everything, we wonāt advance, right?
@tap āIf we all agree with everything, we wonāt advanceā š