6 ms·
The fascinating thing to me about Clojure is that it's so vocally a "practical" language, and yet is a) a Lisp, and b) purely functional[1]. Usually those two t
by _bxg1 6y ago
The fascinating thing to me about Clojure is that it's so vocally a "practical" language, and yet is a) a Lisp, and b) purely functional[1]. Usually those two things are associated with language enthusiasts, and not """pragmatic""" development. In the end it works, clearly, it's just very interesting to see that juxtaposition.
I think it says something interesting about the practical value of higher-brow programming concepts, but also about how important the packaging/marketing/ecosystem is to conveying that value and making it accessible to the masses.
[1] I know it's technically not 100% functional, but all of its messaging highlights that philosophy as a focal point and advantage.
- dgb23 6y agoI think the most important part about Clojure is how ridiculously straight forward it is. Once your REPL is set up and you got used to the predominantly functional API and its vocabulary, you are dealing with an extremely simple, data-driven environment that (almost) never gets in the way. Part of that is due to deviations from traditional Lisps: a more human readable API (first, rest etc.) and less homoiconicity (data structure syntax). But also things like the first class support for names, a baked in, dead simple STM... For me, this is the reason why it is so practical. I'm not good at top-down programming. I can think of and design a system or solution in an abstract way to get a sense of direction. But when it comes to writing code I have to look at small, simple things in isolation, look at the results, change the shapes and build something up. Clojure is very, very good at enabling this kind of dumb, simple, learning-by-doing approach of programming, because everything just works, is easily decomposed and merged together again, with very little ceremony or friction. And when the simple approach reaches its limitations, then there are these extremely expressive tools like multiple dispatch, macros, transducers, spec etc. which all go beyond what most mainstream languages give you.
- junke 6y agoThis is a minor nitpick but please check your facts about other Lisps when comparing them with Clojure. > Part of that is due to deviations from traditional Lisps: a more human readable API (first, rest etc.) first, second, rest ... are defined in Common Lisp > and less homoiconicity (data structure syntax). Clojure is no less homoiconic, you just write vector literals in your code; you could write vector literal to represent code in Common Lisp too, but in fact [], {} etc. are not used by default in CL because they are reserved for the user, so that it can be used for domain-specific purposes.
- dgb23 6y agoThank you for those corrections. My limited Lisp experience before Clojure was with Scheme a very long time ago. I shouldn’t have made these false, blanket statements. Those can be harmful for discussion. In fact I know from reading about CL that it is extremely malleable and that you would be hard pressed to find features that are not present or possible there.
- kazinator 6y ago> I know from reading about :)
- okareaman 6y ago> homoiconicity (data structure syntax) Can someone explain to me why we need a murky word like "homoiconicity" and then explain it as "data structure syntax" (which doesn't clarify much) when "self-modifying code" and "metaprogramming" are crystal clear?
- zodiac 6y agoBoth "self-modifying code" and "metaprogramming" don't mean exactly the same thing to me as "homoiconicity"
- okareaman 6y agoI guess I need to learn Lisp to understand the distinction. My only reference is XLST which is also valid XML. https://en.wikipedia.org/wiki/Homoiconicity https://en.wikipedia.org/wiki/Homoiconicity
- zodiac 6y agoWell, it depends on your exact definition of "self-modifying code" and "metaprogramming", given that it's not like there's an authoratative source you can look up the definitions in. The way I understand the term without additional context, XLST is not "self-modifying code" in the same way malware, certain JIT implementation techniques etc are.
- wtetzner 6y agoHomoiconicity means you're code is defined in terms of the same data structures that are used in programs written in the language. This makes self-modifying code and metaprogramming easier because the language's standard library is already full of functions that operate on those data structures. However, you can have self-modifying code and metaprogramming without homoiconicity, and you can have homoiconicity without support for self-modifying code and metaprogramming.
- itwy 6y ago"juxtaposition"... pun intended?
- yogthos 6y agoClojure isn't actually a purely functional language. It's more of a consenting adults language that guides you towards doing the right thing by default. If you write idiomatic Clojure code, then it will be written in a purely functional style. However, Clojure won't stop you from writing imperative code or adding side effects if it makes sense in your particular scenario. Lisp family of languages also have a lot of tangible and very practical benefits. The syntax is simple very regular, so there's less mental overhead involved in reading it. This helps avoid errors because there's less ambiguity about what the code might mean. The syntax also makes relationships in code explicit, making it more scannable. In most languages it's not immediately obvious if the lines next to each other are related. On the other hand, s-expression syntax effectively provides you with a free diagram where you can see relationships visually. The syntax also facilitates structural editing. Instead of working with lines of text, you work with expressions, and you think in terms of moving blocks of logic around. You can see some examples here https://calva.io/paredit/ https://calva.io/paredit/ The syntax also makes it very easy to serialize code, since code is expressed as plain data structures. This also facilitates powerful metaprogramming facilities. You can apply the language to transforming any code written in the language. Another practical aspect of Lisps is live coding workflow where you connect the editor to the running instance of the application. This creates a very tight feedback loop where you can try things and see the results immediately. This is strictly superior to the traditional workflow where you have to restart the application and build up state to see the results. It's also much faster than using TDD. You can use the REPL for exploration, and then write tests once the code is in the state where it's doing what you want. This is a good read about the workflow https://vvvvalvalval.github.io/posts/what-makes-a-good-repl.html https://vvvvalvalval.github.io/posts/what-makes-a-good-repl.... Here's a talk I co-presented last year that discusses an application my team works on and the specific benefits we found from using Clojure https://www.youtube.com/watch?v=IekPZpfbdaI https://www.youtube.com/watch?v=IekPZpfbdaI
- gleenn 6y ago"... consenting adults that guides you towards doing the right thing by default..." really hits the nail on the head. I do a lot of Java interop at work, which is a necessary evil, but once I'm in Clojure code I'm happy to be gently pushed to be more functional, immutable, have less state, etc etc. Also, thanks for all your great work Yogthos, Luminus is an amazing contribution to the Clojure ecosystem as well as all your other libraries!
- amelius 6y ago> The fascinating thing to me about Clojure is that it's so vocally a "practical" language I tried Clojure, but the startup times were too large to the point where it became impractical. Especially for small scripts.
- gotts 6y agoHave you tried Babashka?
- didibus 6y agoIf you read the history, you'll see that small scripts was never a use case targeted by Rich Hickey. It was focused on information systems programming, where a few seconds of startup time is a blip on the full running time of the application. That said, slow startup times are only true of Clojure JVM. ClojureScript and Clojure babashka, for example, both start fast enough for small scripts. Also, seems the JVM is slowly improving in startup time department. I was surprised to see that a hello world is now down to 800ms start time on my 2011 laptop with Java 14. It was 3s before with Java 8 on the same laptop. For comparison, ClojureScript hello world was 550ms, and babashka hello world was 36ms. Python hello world was 68ms and Ruby was 111ms.
- omaranto 6y ago> Also, seems the JVM is slowly improving in startup time department. It's not the JVM that makes Clojure JVM slow to start up, try comparing hello world in Java vs hello world in Clojure.
- didibus 6y agoIt's true that Java hello world will be faster than Clojure JVM hello world. That said, a big Java application with lots of classes to load, and lots of static initializers (which would approach the same number as what Clojure requires to be loaded and initialized) would take as much time as it does for Clojure. So when people say that part of the slow startup is Clojure's fault, they mean more that it is implemented in a way that the JVM isn't very fast at starting. But if you look at Clojure implemented on other runtimes, like ClojureScript, the startup times are much faster, because the NodeJS runtime is much faster to start and initialize everything than the JVM is. In effect, if the JVM improves startup times, so will Clojure JVM's startup times be improved. That's why I see this drastic difference between a Clojure hello world on Java 8 vs Java 14.