Fork me on GitHub
#clojure
<
2024-06-06
>
slipset05:06:18

I’m curious wether there is any documentation around the introduction of the #( reader macro. I’m sort of assuming that (fn [..] ..) already existed, and wondering why this extra syntax was introduced?

andy.fingerhut07:06:26

It was there in Clojure 1.0, so you'd have to go back further than that to find anything about its introduction.

daveliepmann07:06:53

This is an early (first?) announcement of it https://groups.google.com/g/clojure/c/uDEbsBN_HpM/m/1kVI3MPs7pUJ My read of the thread is that (fn [...] ...) did exist first

💯 1
rich 1
andy.fingerhut07:06:19

Wow, good find!

🙏 1
slipset07:06:13

Nice! Thanks for digging that out. Very interesting thread indeed.

👍 1
daveliepmann08:06:50

Kind of ironic that this particular shorthand syntax was motivated by the Java side of Clojure's heritage, rather than CL (which only had lambdas I guess?). Reverse of how I usually think about Clojure's heritage of concision.

phill08:06:03

It may help to remember, when considering the motivation for #(...), that anonymous functions were needed in more places back in the days before Clojure 1.12.

borkdude09:06:21

I could do without #() if I was forced to

4
Ingy döt Net08:06:19

I met up with @U03B2SRNYTY and his friend yesterday for coffee in London (I'm visiting there) and talk about YAMLScript. YS uses a \() syntax because using # is problematic in YAML (comment char) and also because Haskell uses \ for anonymous functions since https://wiki.haskell.org/Anonymous_function We were agreeing that it wasn't really that useful given (fn […] …).

Ingy döt Net08:06:27

@U0HG4EHMH can you elaborate on the 1.12 comment, for us younger Clojurians? 🙂

daveliepmann09:06:25

@U05H8N9V0HZ > Clojure programmers often want to use Java methods in higher-order functions (e.g. passing a Java method to map). Until now, this has required programmers to manually wrap methods in functions [i.e. #(...)]. ... With this [1.12] release, programmers can now use Java qualified method symbols as ordinary functions in value contexts - the compiler will automatically generate the wrapping function. https://clojure.org/news/2024/02/08/1-12-alpha6#method_values

Ingy döt Net09:06:21

Ah, dot interop stuff?

daveliepmann09:06:30

so (map #(Integer/parseInt %) xs) used to be necessary, and now (map Integer/parseInt xs) suffices

daveliepmann09:06:55

you're welcome 🙂

slipset09:06:38

FWIW @U05H8N9V0HZ I’m in agreement with you > We were agreeing that it wasn’t really that useful given (fn […] …). And this was in many ways why I posted the original post, “Why, when given the (fn […] …) form, would one introduce #(…% …) ?” I would not have chosen to do so, and I’m somewhat surprised that Rich chose to introduce it as saves a couple of chars of typing at the cost of introducing new syntax and concepts.

Ingy döt Net09:06:10

Fun fact: In YS you can't use % for %1 in \(…) because I wanted % to be the rem operator:

$ ys -c -e 'a =: b % (c %% d)'
(def a (rem b (mod c d)))

daveliepmann09:06:27

> saves a couple of chars of typing at the cost of introducing new syntax and concepts :destructuring enters the chat:

slipset09:06:33

IMO destructuring provides much more value, but doesn’t really introduce new syntax, as the destructuring thing is “just” a map, albeit with some specific keys and semantics.

slipset09:06:07

(defn foo [{:keys [bar baz] :as qix}] ...)
Tells me that bar and baz are the important bits of qix in this fn.

daveliepmann09:06:30

I think it's a matter of taste. Concision is an important Clojure value and I appreciate not needing to name my parameters in #(...). Destructuring feels to me like one of the largest areas of Clojure syntax. There are just so many options to combine in myriad ways. (And it's not just a map — sequential destructuring is a vector.) I see the benefits but it can get gnarly.

Ingy döt Net09:06:25

Yesterday we really got into destructuring. I personally (having used destructuring in many langs) find

(let [{:keys [a b c]} d]
and want to be able to
.{a b c} =: d
but then @U03B2SRNYTY introduced me to https://github.com/noprompt/meander?tab=readme-ov-file#meander%CE%B5 which is over the top!

🧡 1
slipset09:06:43

Totally agree that destructuring gets gnarly very fast. I very seldom do much more than one level of destructuring, I find it both unreadable and a sign that you’re not really encapsulating stuff well enough

1
Ingy döt Net09:06:24

Also read or watched somewhere (maybe Rich?) that destructuring can bind you too tightly to a given API.

phill10:06:38

Around here, we believe that destructuring is OK in moderation. After all, any construct can be overused to the point of illegibility... e.g., after forty levels of nested vectors, a person might lose count. Even water is bad, if you drown in it.

1
Ingy döt Net11:06:36

I use it whenever I can (shallowly) and have yet to drown.

Ludger Solbach08:06:49

I'm using tools.cli and have a boolean option --model-warnings with a :default true. Is it possible to set it to false at the command line? --model-wanings false or --no-model-warnings don't work. Any ideas?

p-himik08:06:35

How did you define the option?

Ludger Solbach08:06:27

[nil "--model-warnings" "Returns warnings for the loaded model" :default true]

p-himik08:06:37

Use "--[no-]model-warnings" instead. The README of tools.cli has an example.

👍 1
Ludger Solbach08:06:54

Overlooked it. I knew it should be possible somehow.

Ludger Solbach08:06:09

Works like a treat, thx.

👍 1
김태희(taehee kim)09:06:40

Could anyone please let me know if there is an open source tool to measure the Cognitive Complexity of clojure codes? https://www.sonarsource.com/blog/cognitive-complexity-because-testability-understandability/

김태희(taehee kim)09:06:00

It generate a report like this

p-himik09:06:25

You can try searching in #C06MAR553 and with https://phronmophobic.github.io/dewey/search.html. But FWIW I've never heard about such a tool for Clojure. Maybe Sabik can be adapted to Clojure, dunno.

🙌 1
김태희(taehee kim)09:06:37

Thanks! There is https://github.com/lokori/uncomplexor it measure Cyclomatic Complexity like thing. I may have to make it myself. It is on my "Someday/Maybe" list 😂

👀 1
respatialized11:06:46

given how simple the rules are, it might be relatively easy to use something like rewrite-clj's https://cljdoc.org/d/rewrite-clj/rewrite-clj/1.1.47/api/rewrite-clj.zip to traverse the forms and perform the counts. that said, I think that a purely syntactic measure of "cognitive" complexity is not likely to correlate that much with how maintainable code is, even if it may sometimes be a useful rule of thumb for refactoring.

🙌 1
john13:06:28

I was actually curious about a clojure cyclomatic complexity checker recently, thanks

emccue12:06:02

I know this is a tangent

emccue12:06:16

but i'm reading through the linked sonar paper

emccue12:06:45

very much disagree with this

p-himik14:06:55

"Incent good coding practices" => "ignore features that make code more readable"...what? > "this operator makes things immediately clear, so it's ignored" At this point, I feel like I'm missing something. As if someone's telling me that plain water always tastes salty.

p-himik14:06:08

I would understand if "Cognitive Complexity" meant the understanding of what's going on at the conceptual level - not at the language level. But the section on screenshot talks about about "good coding practices" and... some other things.

emccue14:06:20

Yeah...it's like "we like this feature and so to promote it's use we are going to ignore our criteria for it"

1
emccue14:06:39

At least cyclomatic complexity isn't pretending to be more than a heuristic

emccue14:06:29

I don't even disagree with having a heuristic, but calling it "cognitive complexity" is too far.

emccue14:06:17

?. Is controversial specifically because while it makes code easier to write it's a very small visual signal for a branch in logic. I.E. harder to read

p-himik14:06:07

Ah, then my understanding of the screenshot is probably wrong. I thought it was saying that there's no distinction of the two versions in their cognitive complexity. Whereas I myself would say that the version on the right is less complex. ?. is exactly the same as some-> and I myself don't see either of them as a branch in logic. To me, it's more similar to multiplication - you don't expand * into things like "multiply absolute values of all the arguments, count the number of negative signs, assign the negative sign to the result if the count is odd".

p-himik14:06:47

In other words, I view ?. as a single operation that's conceptually different from an if even if that if is syntactically equivalent to ?.. It's the same with nil punning. Or with NULL propagation in SQL. And with probably many other things I'm not even aware of.

emccue14:06:41

Like I said, controversial

emccue14:06:37

But some-> takes more visual real estate and also has indented arguments usually.

emccue14:06:03

Imagine if we had a clojure dialect where for every function we could add ?. to the end to make it nil safe

emccue14:06:23

Like (conj?. [] a)

emccue14:06:17

That's just a different level of readability than (some-> [] (conj a))

p-himik14:06:59

That would be hard for me go gauge based on imagination alone because habits and pattern recognition take time to form. It might very well be something completely fine and maybe even something the other me would prefer over current Clojure if that dialect was the one he started with.

exitsandman16:06:29

there is a big advantage in keeping things simple. Giving up the slightest bit of readability leads to some-> being an easily written macro as opposed to a change in the syntax specification of the language.

p-himik16:06:20

But there are also disadvantages, otherwise we would be all spitting out 1s and 0s which are the epitome of simplicity. :)

p-himik16:06:12

A comment to the edit - that's a problem not of the change but of the language. We have macros, many things are much, much easier for us.

exitsandman16:06:18

and implementing the most language features possible as macros rather than at what effectively is the textual level makes it much easier to keep that advantage!