But the mental model is fundamentally different. It's not like you write a bunch of code, set a breakpoint and see what things are. You essentially boot up a lisp image and then you make changes to it. It's more like carving out a statue from a piece of rock rather than building a statue layer by layer.
Data shapes in Clojure typically explicit and consistent. The context usually makes things quite obvious. Data is self-describing - you can just look at a map and immediately see its structure and contents - the keywords serve as explicit labels and the data, well... is just fucking data. That kind of "data transparency" makes Clojure code easier to reason about.
In contrast, in many other PLs, you often need to know the class definition (or some other obscured shit) to understand what properties exist or are accessible. The object's internal state may be encapsulated/hidden, and its representation might be spread across a class hierarchy. You often can't even just print it to see what's inside it in a meaningful way. And of course, it makes nearly impossible to navigate such codebases without static types.
And of course the REPL - it simply feels extremely liberating, being able to connect to some remote service, running in a container or k8s pod and directly manipulate it. It feels like walking through walls while building a map in a video game. Almost like some magic that allows you to inspect, debug, and modify production systems in real-time, safely and interactively, without stopping or redeploying them.
Not to mention that Clojure does have very powerful type systems, although of course, skeptics would argue that Malli and Spec are not "true" types and they'd be missing the point - they are intentionally different tools solving real problems pragmatically. They can be used for runtime validation when and where you need it. They can be easily manipulated as data. They have dynamic validation mechanisms that static types just can't easily express.
One thing I learned after using dozens of different programming languages - you can't just simply pick one feature or aspect in any of them and say: "it's great or horrible because of one specific thing", because programming languages are complex ecosystems where features interact and complement each other in subtle ways. A language's true value emerges from how all its parts work together, e.g.,
- Clojure's dynamic nature + REPL + data orientation
- Haskell's type system + purity + lazy evaluation
- Erlang's processes + supervision + fault tolerance
What might seem like a weakness in isolation often enables strengths in combination with other features. The language's philosophy, tooling, and community also play crucial roles in the overall development experience.
If one says: "I can't use Clojure because it doesn't have static types", they probably have learned little about the trade they chose to pursue.
Sure, static typing is great, but perhaps you have no idea what it actually feels like - spinning up a Clojurescript REPL and being able to interactively "click" and "browse" through the web app programmatically, controlling its entire lifecycle directly from your editor. Similarly, you can do the same thing with remote service running in a kubernetes pod. It's literally like playing a video game while coding. It's immensely fun and unbelievably productive.
I mean, I love Clojure, and used it for personal and work projects for 10+ years, some of which have hundreds of stars on github. But I cannot count the time wasted to spot issues where a map was actually a list of maps. Here Elixir is doing the right thing - adding gradual typing.
Sorry, I'm having hard time believing that. I don't know when was the last time you've used the language, but today there are so many different ways to easily see and analyze the data you're dealing with in Clojure - there are tons of ways in CIDER, if you don't use Emacs - there are numerous ways of doing it in Calva (VSCode) and Cursive (IntelliJ), even Sublime. There are tools Like Portal, immensely capable debuggers like Flowstorm, etc. You can visualize the data, slice it, dice it, group it and sort it - all interactively, with extreme ease.
I'm glad you've found great fondness for Elixir, it is, indeed a great language - hugely inspired by Clojure btw.
You still don't need to bash other tools for no good reason. It really does sound fake - not a single Clojure developer, after using it for more than a decade, would call a Lisp REPL "a band-aid and not a solution". It smells more like someone with no idea of how the tool actually works.
I found spec very useful and damn expressive (and I miss it in other languages), but again that's runtime. I know Rich says such errors are "trivial", but they waste your time (at least mine).
if x > 10:
call_my_function 10
else:
call_my_function "foo"
Can't you see that unless you test every path, you won't know what type you will receive??There's a wide spectrum of correctness guaranties in programming - dynamic weak, dynamic strong, static, dependent, runtime validation & generative testing, refinement types, formal verification, etc.
Sure, if your domain needs extreme level of correctness (like in aerospace or medical devices) you do need formal methods and static typing just isn't enough.
Clojure is very fine, and maybe even more than just fine for certain domains - pragmatically it's been proven to be excellent e.g., in fintech and data analysis.
> Can't you see that unless you test every path ...
Sure, thinking in types is crucial, no matter what PL you use. And, technically speaking, yes, I agree, you do need to know all paths to be 100% certain about types. But that is true even with static typing - you still need to test logical correctness of all paths. Static typing isn't some panacea - magical cure for buggy software. There's not a single paradigm, technique, design pattern, or set of ideas that guarantee excellent results. Looking at any language from a single angle of where it stands in that spectrum of correctness guaranties is simple naivety. Clojure BY DESIGN is dynamically typed, in return it gives you several other tools to help writing software.
There's an entire class of applications that requires significantly more effort and mental overhead to build using other languages. Just watch some Hyperfiddle/Electric demos and feel free to contemplate what would it take to build similar things in some other PL, statically typed or whatnot. https://www.youtube.com/watch?v=nEt06LLQaBY
> And, technically speaking, yes, I agree, you do need to know all paths to be 100% certain about types.
Yes, thank you.