Clojure is indeed mind-expanding. Unfortunately its most compelling ideas don't translate to non-LISPs, so I must sadly disagree with the "learn Clojure" suggestion. It's wild fun, but it's hard to apply the ideas to DayJob.
An example: threading macros. In a language like Haskell, partial application is optimized for left-to-right. `f a` substitutes the first argument; other orders are more awkward. Functions like `map` deliberately place the "most known" arguments first to aid in partial application. If they guess wrong the code gets twisty.
But Clojure's threading macros compose functions, while just letting you say where you want the argument to go:
(as-> [:foo :bar] v
(map name v)
(first v)
(.substring v 1))
Here `as->` creates `v` as a meta-variable which means "the result of the last function". The code seamlessly mixes the declarative and imperative. It's like nothing else.
Sadly no DayJob language has features like this, and Clojure has other weaknesses which become apparent rapidly. Clojure learning will leave you yearning.
> Clojure has other weaknesses which become apparent rapidly.
Clojure has lots of strengths which also become apparent the more you works with it: async, thread-first, thread-last, transducers, core.logic, (partial f a), flexible composition, expressive-ness unrivaled in Dayjob language, hundreds of functions that just work on whatever data you're dealing with, tapping into java "dayjob" libraries without having to deal in actual java. The list goes on.
I've re-written a few applications & libraries from javascript (and other dayjob languages) -> clojure(script). In every case, the lines of code drastically dropped, the functionality expanded, the readability improved, and performance was always on par or better. It's not a silver bullet for everything, but its strengths far outweigh its weaknesses. Like any good mind-expanding drug/language.
> Clojure learning will leave you yearning.
It has been my experience with learning clojure that with each new problem, it has left me yearning ... to learn the more elegant, composable, flexible, robust solution ... in clojure! YMMV.
> Clojure is indeed mind-expanding. Unfortunately its most compelling ideas don't translate to non-LISPs, so I must sadly disagree with the "learn Clojure" suggestion. It's wild fun, but it's hard to apply the ideas to DayJob.
I must say, having learned Clojure (and ClojureScript) and used it in production in my day job (we even still have one ClojureScript project in production), I strongly disagree. I would probably not choose to use it again, mostly because I've come to prefer static typing, but quite a lot of what I learned from learning it (and learning its idioms) has greatly improved my work in other languages.
In particular, Clojure's approach to state is something you can (mostly) apply in most mainstream languages. Handling most runtime state as immutable values, with clear and explicit use of mutable state for the cases where it's either necessary or makes the code easier to understand/more maintainable, is a huge boon for developers working in imperative languages.
In my current job, I've seen the quality of projects improve drastically as I've lead by example with that approach, and as I've asked for changes like it in code review. I've seen the volume and severity of bugs decrease, developer productivity improve, and morale trend upward.
Never used Lisp, but this sounds like a case of offering you loads of cool stuff when writing new code, which in turn will make debugging the code an absolute nightmare. This is based on my experience with mixed metaphor languages like Python. You can do some clever stuff like generating functions dynamically and passing them around, but when you need to debug these bits of code they can be a nightmare. Does Lisp improve on this in any way?
I believe that macros can increase the complexity of debugging.
However, I believe they're much more debuggable than dynamically-generated functions in most languages. There's another layer of translation from your baseline code, but due to the nature of macros, you can usually just step right into them and see the expanded, generated macro code, if my rusty memories of debugging elisp are correct.
Here's one person reading about Common Lisp's debugging infrastructure, FWIW.
for me it's hard to separate it from reading SICP, which as a self taught developer, I feel brought me to a different level of understanding concepts like immutability, the shortcomings of oop, streams, eval apply and so on.
I’ll second this. You don’t even have to go all in and spend a year programming it. Just dipping your toe into SICP/Lisp every once in a while is enough to shock you into realizing that there’s a much broader scope of possibilities in programming that has not been effectively exposed to you or the masses.
SICP really gives you a “full-stack” appreciation for software (from applications down to compilers and interpreters). It’s horizon-expanding.