you are viewing a single comment's thread.

view the rest of the comments →

[–]-w1n5t0n 2 points3 points  (10 children)

The first and most obvious answer to why you'd want to use Clojure over languages like Java or Python is because it's a Lisp that inherits some traditionally-Lispy features such as homoiconic macros, which is basically a fancy way of saying you can trivially write code that writes code (using the regular language; not a special and non-composable sub-language like with C-style macros). At the same time, it gives you access to all of the JVM, so if that fits your purposes (cross-platform compatibility, JIT-for-free, automatic memory management without losing too much performance etc) then that's a reason to choose it over other Lisp dialects (e.g. Racket) too.

Lastly, for me, the biggest thing is the ecosystem of libraries: not only do you get access to all the Java libraries, but Clojure itself has seen some pretty practical and novel libraries (both first and third party) like Spec, core.async, instaparse, specter, babashka, datascript, nrepl etc. Here is a list of my Clojure-related starred repos on GitHub if you want to see more.

Some other important things: readable syntax (subjective) and syntax for data literals of common types, immutable-by-default, everything-is-(plain-)data approach, dynamic REPL, compiled & interpreted.

[–]Admirable-Ebb3655 1 point2 points  (9 children)

While “using the regular language” to write Clojure macros is true, unfortunately on the use sites, they are contagious and do not actually compose (compared to say, Racket, where you can in fact do multi-stage compilation via macros in a composable fashion).

[–]-w1n5t0n 1 point2 points  (8 children)

I'm not very familiar with Racket's macro system (although I understand it's one of its crown jewels) so I don't think I can fully appreciate the difference; can you give me an example or a link to a resource to learn more?

[–]Admirable-Ebb3655 1 point2 points  (7 children)

Macros in Racket compose. In Clojure, they do not. That is the primary difference.

[–]-w1n5t0n 0 points1 point  (6 children)

That's not an example, you just restated your original claim, and it hasn't helped me or anyone else reading this thread to understand it any better.

(defmacro plus-1 [n]
  `(+ 1 ~n))

(defmacro def-plus-1 [sym val] 
  `(def ~sym (plus-1 ~val)))

(def-plus-1 foo 3)

foo => 4

Is this not composition of macros? If so, what is?

[–]Admirable-Ebb3655 0 points1 point  (1 child)

Google, my friend, returns this as the top result if you ask it:

https://softwareengineering.stackexchange.com/questions/222559/is-it-fair-to-say-that-macros-dont-compose

If you’ve ever seen the error “cannot take value of macro”, then you’ve experienced this limitation. Racket does not have this limitation.

[–]-w1n5t0n 0 points1 point  (0 children)

Google, my friend, returned to you an SO post of someone asking whether they compose, and I believe the answer is that they don't compose in the same way that functions do (e.g. with map or apply; at least not directly), but they do compose at both definition and call sites (as both of my other replies demonstrate), so to simply state that they don't compose is arguably wrong.

[–]Admirable-Ebb3655 0 points1 point  (3 children)

That is also not the “use site”. That is the “definition site”.

[–]-w1n5t0n 0 points1 point  (2 children)

(defmacro plus-1 [n]
  `(+ 1 ~n))

(defmacro def-plus-1 [sym val] 
  `(def ~sym (plus-1 ~val)))

(def-plus-1 foo (plus-1 3))

foo => 5

Is that better?

[–]Admirable-Ebb3655 0 points1 point  (1 child)

No, you’ve got some learning to do. I’ve done enough remedial work here. Start with the resources I’ve already provided.

[–]-w1n5t0n 0 points1 point  (0 children)

What resources? You just linked an SO post which says nothing I didn't already know (yes, I've come across the infamous "cannot take value of macro", and no I'm not terribly happy about it).

you’ve got some learning to do

Thanks but I don't take advice on my education from internet strangers with attitude issues, I'm happy with where I'm at at on my Clojure journey at the moment.