I'm trying to learn Clojure at the moment at the recommendation of Paul Graham and other technologists whom I greatly respect. But as I work through various coding challenges in an attempt to come to grips with the language, I have yet to encounter a single problem that is solved more elegantly in Clojure than the equivalent Pythonic solution. I am really trying to have an open mind, but I don't want to join a cult, either.
It really feels at this point like Python has subsumed the best features of every dynamically typed language.
Typically, people endorse Clojure for the following reasons:
1. It's functional!
OK, well, all the higher order functions exist in Python, too, but in fact you wouldn't want to use them anyway because in Python you have list comprehensions, which, it turns out, usually leads to an even more readable solution.
2. REPL-driven development!
Python also has a REPL. True, it isn't the best REPL imaginable, but as far as I can tell it has feature parity with Clojure's! Both are missing the ability to fix errors live in a breakout REPL like you would find in a true LISP REPL.
3. Macros! Code is data! You can easily create your own DSL!
OK, maybe. But actually, in Clojure I've gathered the impression that macros are looked down upon, a feature of last resort, unlike in other LISPs. I also can't recall ever using Python and wishing I could replace its syntax with a DSL, since it is already so expressive and flexible. But admittedly that might be a limitation with my own imagination and experience.
People tend to say all these things in favor of Clojure, but when you actually investigate them they seem quite flimsy. Meanwhile, for a language like Python the value product is clear and obvious. Where else are you going to do your machine learning, for example?
I really am not trying to be an asshole to people who do enjoy and like Clojure, because I want to be one of you! I just need some reason to continue learning because clearly I haven't yet grokked the benefits. If anybody could concisely explain the advantages Clojure has over a language like Python (speed, maybe?) which do not fall apart under close scrutiny I would be grateful.
1. Unlike Python, Clojure actually is functional and is optimized for it, with persistent immutable data structures and a huge library for functional transformations. You get faster, more expressive code in Clojure than in Python if you’re doing FP.
2. The REPL is not on par. You can run an in-editor REPL and build your entire program in a REPL session. Combined with tap you can visualize your output on the fly.
3. Macros are used, not looked down upon. But they are discouraged when not needed. Much of the power and succinctness of the language comes from macros. Boilerplate is a solved problem.
There are a lot of subtle and less obvious advantages too, like namespaced keywords, a highly productive and creative niche community, a very composable and simple library ecosystem and a huge emphasis on stability.
But disadvantages exist too. The Clojure toolchain has a nice surface but is more involved under the hood. There’s also not a single happy path framework for the web, but rather a variety of library options. Finally, Clojure isn’t the best fit for certain types of programs, it’s really optimized for applications and data centric stuff.
> [Clojure] is really optimized for [\snip] data centric stuff
Not sure what this means. Stu Halloway made a comment to the effect of "all programming is ultimately data transformations". Honest question here, what programming language is NOT for data-centric stuff?
I find that when I'm working in verbose programming languages: Java, C#, it doesn't feel like all programming is data transformations, when in reality it is.
> The REPL is not on par. You can run an in-editor REPL and build your entire program in a REPL session. Combined with tap you can visualize your output on the fly.
I would like to point out, for fellow Lispers who enjoy REPL driven development, that you can do this with Python in Emacs via Elpy. `elpy-shell-send-statement` is something like `eval-last-sexp` or `geiser-eval-last-sexp` or... etc.
> The REPL is not on par. You can run an in-editor REPL and build your entire program in a REPL session. Combined with tap you can visualize your output on the fly.
In Python you could just open up a notebook if you wanted that.
-Clojure also has list comprehension, so use what you like.
-You cannot compare the repls, at all. If used standalone, sure, but that's not how it's done. You send s-expressions for evaluation, from your editor, and that's the magic. There does not exist any kind of equivalent repl-based workflow for python or really anything that isn't a lisp. Fix errors live is literally what it excels at, so I'm not sure what you mean by that.
-Macros get messy and avoiding them when possible is good, yes. Still, the power is there. But as far as DSLish stuff I prefer manipulating and "running" straight data structures, like re-frame events. Data is code :)
Also:
-CLJS
-Edn+transit
-Datomic
-Live exploration/visualization tooling. As in above, or Portal, or re-frame10x/re-frisk, dev tools, dirac... obviously first you need your basic environment sorted. I use vim with conjure.
> 1. It's functional! OK, well, all the higher order functions exist in Python, too, but in fact you wouldn't want to use them anyway because in Python you have list comprehensions, which, it turns out, usually leads to an even more readable solution.
My experience is that this is not the case.
Sure, list comprehensions are nice for simple things. But once they start getting complicated - for example nested iteration - they start to look fugly. This is a big reason why I strongly prefer ruby over python - I get access to reduce[1] which is substantially more powerful than map and filter. And the syntax for complex expressions stays easy to understand.
I get that that may not be a path that you want to travel, but for me one of the best parts of Clojure is all of the built in functional bits.
> 2. REPL-driven development! Python also has a REPL. True, it isn't the best REPL imaginable, but as far as I can tell it has feature parity with Clojure's! Both are missing the ability to fix errors live in a breakout REPL like you would find in a true LISP REPL.
If you like using the REPL and haven't tried it, ptpython is amazing. A huge upgrade over the default REPL.
> 3. Macros! Code is data! You can easily create your own DSL! OK, maybe. But actually, in Clojure I've gathered the impression that macros are looked down upon, a feature of last resort, unlike in other LISPs. I also can't recall ever using Python and wishing I could replace its syntax with a DSL, since it is already so expressive and flexible. But admittedly that might be a limitation with my own imagination and experience.
Another way to look at macros is that they make it possible to integrate the meta-programming environment - stuff like swagger API generators - into your coding environment.
---
1. Yes, I know that python has map, filter, and reduce. But they're all gimped by the way python implements lambdas. Which is sort of necessary due to meaningful whitespace. And I could just write regular functions instead, but it's not very ergonomic at that point. And it's also un-pythonic.
> But once they start getting complicated - for example nested iteration - they start to look fugly.
Then don't do it. Un-nest them always. Simples.
> I get access to reduce[1] which is substantially more powerful than map and filter
Reduce is orthogonal to map/filter.
> Yes, I know that python has map, filter, and reduce. But they're all gimped
No they're not: map [x*2 for x in y], [x*2 for x in y if x > 3] (Syntax not tested, am a bit rusty so may be wrong). Okay, you're not providing a function as a parameter but most of the time with map and filter, that parameter is a constant function not a variable so I still hold this is true. Reduce would be nice as a comprehension, if that's possible.
> by the way python implements lambdas. Which is sort of necessary due to meaningful whitespace
I don't believe whitespace is the problem here. They could fix that pretty easily. I'm really unhappy with python's expression-only lambdas, they do suck.
What are you hoping to gain from learning Clojure?
Have you seen how it’s management of state is different to Python’s in how it allows much closer control of data sharing? That opens up really nice concurrency models, and makes thinking about how data changes over time much more predictable (and powerful).
Does your editor let you manipulate the code as a lisp? The tree-based nature of the code allows for incredible automatic re-organisation of it, on the fly as you need to reshape it.
Have you used transducers yet? They let you specify the essence of a computation and apply it in different contexts - to a series of in-memory values, or values arriving over a network pipe, or any other source, without having to know in advance what that source is
But if these don’t appeal to you or you don’t see the benefits of them then maybe it isn’t for you - which is totally fine. Python can let you express this stuff too, albeit in clunkier ways at times and with a less pleasant refactoring experience. The python repl is also less powerful and not advocated for as a development tool in the same way Clojure’s is.
It really depends on your end-goal. If you’ve not been frustrated by the idioms Python gives you changing languages might feel a little pointless. I’ve used both and I’m far more productive in Clojure. It really rewards study and practice, and grows with you. Python is fine, but it’s a means to an end for me - get in, just get it done, try to remember the irregular syntax, weird build specification, get over white-space layout, use print debugging to get over the repl… it’s not my favourite but it’s perfectly usable.
One of the most obvious reasons is concurrency. Clojure provides excellent concurrency and parallelism primitives, immutability by default and STM for when you need state. Python's concurrency story is downright bad to the point where I wouldn't write any complex application in it.
Then there's performance. Clojure is usually within Java range and when it isn't interop is no problem. Python is slow as molasses, probably at least 10x slower if not more than anything running on the JVM with nothing to show for it.
For Machine Learning Python is fine because you're typically writing ~300 lines of glue code.
- Persistent data structures with structural sharing
- A real Lisp REPL not a Python console
- 650 builtins to wrangle data in ways yo never imagined possible
- The JVM and JS platforms
- Rich Hickey
That's a pretty good deal I think. By contrast Python has crippled single statement lambdas, late binding footguns and weird scoping. No contest. Ruby is much better at what Python tries to be as it wasn't designed by a BDFL who dislikes functional programming. Python's popularity is the result of Google's adoption and a marketing exercise in academia. For quality of design Python ranks near the bottom.
i know it wasn’t a serious list item but including “rich hickey” in a reply to someone who expressed reservations about joining a cult is probably the opposite of convincing
The two REPLs are not the same, unless editor-integrated Python REPLs have gone through a revolution since I last checked. See https://lambdaisland.com/blog/29-12-2017-the-bare-minimum-cl... and circa 22:49.90 of [Stop Writing Dead Programs][1], on the topic of interacting with a live system as you write it.
As someone who writes more Python than Clojure these days, Python's limited lambdas are a regular source of frustration. Additionally, Clojure's first-class data structures are sorely missed in Python.
> 2. REPL-driven development!
The huge drawback IMHO that rarely gets discussed is the ability to change modules in Python's interactive interpreter (Clojure's analog is the namespace). For example, in the context of a web app, adding a new view in some views module, then swapping to the routes module and adding the adding a new route to wire up the view. Additionally, there's no built-in way to connect to the interpreter, as manually typing in a REPL is not the usual flow. To me this makes Python's interpreter unusable for anything but toy examples.
> 3. Macros!
Clojure is less macro-dependent than other lisps, but in most projects I use, there are one or two that really help clean things up. If you look to other modern languages that have macros (for example, Rust), I think the same idea applies.
I had a very similar experience and ultimately gave up, at least until I see more of the evidence you're asking for.
The concise way of writing Clojure/Lisp, which is often praised as one of its benefit (shorter code!) to me often just made it harder to understand.
Also, coming from TypeScript, I was really missing the static typing - TDD was not a sufficient replacement for me, as I feel that again the main benefit of static typing is more easy understanding when reading other people's code.
Since you mentioned PG, here's a very good counter point given by Jonathan Blow to what he says, and a discussion between the two (rare to see on HN): https://news.ycombinator.com/item?id=21237636
Clojure's value is all in the what you're not doing, that can be hard to explain if you've never experienced the pain it tackles
So I'm sure as part of your learning you will have created a web app maybe a rest end point or nextJS, next I want you to go check out Clojure Electric take a look at some of the demos and try and replicate it in JavaScript with any framework in less code
If you're convinced of the potential for the language install clj-kondo, parinfer, paredit into your editor and never type directly into the repl
Unfortunately it's nearly impossible to learn Clojure without tooling support so find that Clojure plugin for your editor and don't ignore the other tooling before starting
How exactly do you use clojure's repl? You're not supposed to write things in the repl window.
As for functional programming, if your rebuttal is that python has list comprehensions, you still need to do some more digging into it. I suggest you read Peter Norvig's pytudes, he writes python in a functional way and uses both higher order functions (which are there, but really meh) and list comprehensions. They are not the same thing. Clojure also has immutable structures which is imo just as important for functional programming.
Not to say that python can't be used for it (pytudes really looks like art). For clojure maybe you can watch the parent of the dead series on YouTube (there's an ongoing reboot of the series). The repl workflow is so different from other languages that you really need to see people code in clojure live to understand it.
> The repl workflow is so different from other languages that you really need to see people code in clojure live to understand it.
Just wanted to add a channel to this that I recently came across with a few videos about different REPL use. I also suggest seeing how other people use it, I keep picking up a few new tricks here and there by doing so.
I've written the EXACT same thing on here multiple times over the years haha. After learning Python, I tried to find the next best thing, but all the big recommendations were more of a pain to do anything simple. Perhaps they win out big on long projects or under heavy server loads, but for my needs...Python hits a certain set of optimal trade offs that is hard to beat.
It's true that dynlangs sipped a lot of what made lisp better before, that said i'm often tired of comprehension lists, sometimes I really want to have a thread with generic higher order functions.
Clojure has immutable first data too, it can shield you from a lot of issues, especially when working with young devs. I still remember some python code some guy made. 3 files, 5 pages each, tons of loops over mutable dicts. Side effects everywhere. The actual logic fits in 50 lines of code with functional idioms.
All lisps features are now pushed into rare needs/researchy contexts, the mainstream absorbed a lot. See clojurescript electric to see an interesting DSL-y idea. And in a way, I consider django a half DSL (lots of classes are static descriptions assembled in a tree of faux-dataclasses.. it's a DSL without the name or ease).
Enjoy python, but keep an eye on other languages (be it clojure, sml, haskell, prolog, apl, perl6) it's always interesting.
> 2. REPL-driven development! Python also has a REPL. True, it isn't the best REPL imaginable, but as far as I can tell it has feature parity with Clojure's!
I'd say that the value of learning a lisp-y language is that it is very different from mainstream languages (but you'll notice that modern languages have borrowed many features, sometimes in a strange way). Learning a lisp is good because it can change the way you think, not because it's some magic technological wand that will solve all your problems.
The REPL comment above, though, shows that you might not be developing in a very idiomatic way. Clojure is usually developed with an editor (emacs, but there are others like Conjure/nvim & Calva/vscode) that sends s-expressions to be evaluated by a separate process (the REPL). The expression's value is sent back and displayed in line with the code.
The key thing here is that instead of building your program all at once and running it as a whole, you build the program one expression at a time, and when you are ready you can evaluate the program as a whole. It's hard to pick up these habits if you are working in isolation, but it is a very different way to develop software, and is big reason people like lisp-y languages.
Many languages provide a 'REPL', but don't support this style of development, which is really what people who know are crowing about.
A few things to consider:
* Immutable by default.
* Not OOP, if that's your thing
* Access to jvm libraries
* Good concurrency model
* Clojurians slack is excellent, your questions are often answered by core language maintainers
* Clojurescript is great
On macros, they are not discouraged, it is just encouraged to use them only when needed. Lots of very useful libraries are based on them, and much of the core language is too.
From a language perspective I think it is pretty close. I give clojure the nod because of default immutable data, which helps force the think in terms of transforming input to output.
I also think Clojure wins on other features. Being able to create a one file deployment that packages all of my dependencies (including Clojure) in to a single file. Performance and multi threading both give clojure another bump.
The only reason real reasons you would want to use Clojure over Python are if you need to work/leverage the Java ecosystem (don't want to use Java/Kotlin) and you want a real multithreaded runtime (no GIL).
or when you want immutablity and a functional programming style.
or if you prefer manipulating lisp ast instead of wrestling indentation.
or if you need somewhat decent performance,
or if you need somewhat decent multithreading,
etc etc..
> have yet to encounter a single problem that is solved more elegantly in Clojure than the equivalent Pythonic solution
Despite Lisp being one of the oldest popular languages, now almost 50 years, there must be a reason why it never become mainstream. Until Lisp language developers figure out these reasons and address them, Lisp and its cousins likely remain in academic niche.
Those that do, are you excited about REBL? (If so, why?)
How do they like Datomic in 2023?
Do they miss regular RDMS like MySql and Postgres?
(Came to the comments hoping there would be more comments on Datomic, REBL, etc.
But it just turned into a flame war between Python and Clojure of all things.
Why would a company corner itself with a very niche, closed source database (and performance nightmare with its own query language you can't use anywhere), attached to one programming language when today the open source ecosystem of databases and cloud databases has so many good options and solutions?
Can't Datomic be used with any JVM language? Sure, it's a Clojure-first database (note that Mongo is a JS-first DB), but a major selling point of Clojure is you can use it with Java/Kotlin/etc.
Not that many, actually, if you want your database to be distributed (in any way). Even fewer if you want it to not lose your data. Plus the really good options (FoundationDB) are not "popular". As Barbie once said, "math is hard".
It looks like big chunks of REBL are being pulled into Clojure core:
>Fogus has been mostly focusing on some new tooling derived from REBL and we are hopefully nearing a point of release on that and some additional supporting libs soon as well.
This is important because the core Clojure license is true open source vs REBL which had a semi closed license, so it’s always been a little difficult of a choice for many people.
That's great news. It would be easier to make "ports" of REBL like to a simple cljs app with the major components available. I feel REBL might have a bunch of nav wrappers that I would have to re-implement if I had to start from scratch
It really feels at this point like Python has subsumed the best features of every dynamically typed language.
Typically, people endorse Clojure for the following reasons: 1. It's functional! OK, well, all the higher order functions exist in Python, too, but in fact you wouldn't want to use them anyway because in Python you have list comprehensions, which, it turns out, usually leads to an even more readable solution. 2. REPL-driven development! Python also has a REPL. True, it isn't the best REPL imaginable, but as far as I can tell it has feature parity with Clojure's! Both are missing the ability to fix errors live in a breakout REPL like you would find in a true LISP REPL. 3. Macros! Code is data! You can easily create your own DSL! OK, maybe. But actually, in Clojure I've gathered the impression that macros are looked down upon, a feature of last resort, unlike in other LISPs. I also can't recall ever using Python and wishing I could replace its syntax with a DSL, since it is already so expressive and flexible. But admittedly that might be a limitation with my own imagination and experience.
People tend to say all these things in favor of Clojure, but when you actually investigate them they seem quite flimsy. Meanwhile, for a language like Python the value product is clear and obvious. Where else are you going to do your machine learning, for example?
I really am not trying to be an asshole to people who do enjoy and like Clojure, because I want to be one of you! I just need some reason to continue learning because clearly I haven't yet grokked the benefits. If anybody could concisely explain the advantages Clojure has over a language like Python (speed, maybe?) which do not fall apart under close scrutiny I would be grateful.
2. The REPL is not on par. You can run an in-editor REPL and build your entire program in a REPL session. Combined with tap you can visualize your output on the fly.
3. Macros are used, not looked down upon. But they are discouraged when not needed. Much of the power and succinctness of the language comes from macros. Boilerplate is a solved problem.
There are a lot of subtle and less obvious advantages too, like namespaced keywords, a highly productive and creative niche community, a very composable and simple library ecosystem and a huge emphasis on stability.
But disadvantages exist too. The Clojure toolchain has a nice surface but is more involved under the hood. There’s also not a single happy path framework for the web, but rather a variety of library options. Finally, Clojure isn’t the best fit for certain types of programs, it’s really optimized for applications and data centric stuff.
Not sure what this means. Stu Halloway made a comment to the effect of "all programming is ultimately data transformations". Honest question here, what programming language is NOT for data-centric stuff?
I find that when I'm working in verbose programming languages: Java, C#, it doesn't feel like all programming is data transformations, when in reality it is.
I would like to point out, for fellow Lispers who enjoy REPL driven development, that you can do this with Python in Emacs via Elpy. `elpy-shell-send-statement` is something like `eval-last-sexp` or `geiser-eval-last-sexp` or... etc.
In Python you could just open up a notebook if you wanted that.
Dead Comment
-Clojure also has list comprehension, so use what you like.
-You cannot compare the repls, at all. If used standalone, sure, but that's not how it's done. You send s-expressions for evaluation, from your editor, and that's the magic. There does not exist any kind of equivalent repl-based workflow for python or really anything that isn't a lisp. Fix errors live is literally what it excels at, so I'm not sure what you mean by that.
-Macros get messy and avoiding them when possible is good, yes. Still, the power is there. But as far as DSLish stuff I prefer manipulating and "running" straight data structures, like re-frame events. Data is code :)
Also:
-CLJS
-Edn+transit
-Datomic
-Live exploration/visualization tooling. As in above, or Portal, or re-frame10x/re-frisk, dev tools, dirac... obviously first you need your basic environment sorted. I use vim with conjure.
My experience is that this is not the case.
Sure, list comprehensions are nice for simple things. But once they start getting complicated - for example nested iteration - they start to look fugly. This is a big reason why I strongly prefer ruby over python - I get access to reduce[1] which is substantially more powerful than map and filter. And the syntax for complex expressions stays easy to understand.
I get that that may not be a path that you want to travel, but for me one of the best parts of Clojure is all of the built in functional bits.
> 2. REPL-driven development! Python also has a REPL. True, it isn't the best REPL imaginable, but as far as I can tell it has feature parity with Clojure's! Both are missing the ability to fix errors live in a breakout REPL like you would find in a true LISP REPL.
If you like using the REPL and haven't tried it, ptpython is amazing. A huge upgrade over the default REPL.
> 3. Macros! Code is data! You can easily create your own DSL! OK, maybe. But actually, in Clojure I've gathered the impression that macros are looked down upon, a feature of last resort, unlike in other LISPs. I also can't recall ever using Python and wishing I could replace its syntax with a DSL, since it is already so expressive and flexible. But admittedly that might be a limitation with my own imagination and experience.
Another way to look at macros is that they make it possible to integrate the meta-programming environment - stuff like swagger API generators - into your coding environment.
---
1. Yes, I know that python has map, filter, and reduce. But they're all gimped by the way python implements lambdas. Which is sort of necessary due to meaningful whitespace. And I could just write regular functions instead, but it's not very ergonomic at that point. And it's also un-pythonic.
Then don't do it. Un-nest them always. Simples.
> I get access to reduce[1] which is substantially more powerful than map and filter
Reduce is orthogonal to map/filter.
> Yes, I know that python has map, filter, and reduce. But they're all gimped
No they're not: map [x*2 for x in y], [x*2 for x in y if x > 3] (Syntax not tested, am a bit rusty so may be wrong). Okay, you're not providing a function as a parameter but most of the time with map and filter, that parameter is a constant function not a variable so I still hold this is true. Reduce would be nice as a comprehension, if that's possible.
> by the way python implements lambdas. Which is sort of necessary due to meaningful whitespace
I don't believe whitespace is the problem here. They could fix that pretty easily. I'm really unhappy with python's expression-only lambdas, they do suck.
Have you seen how it’s management of state is different to Python’s in how it allows much closer control of data sharing? That opens up really nice concurrency models, and makes thinking about how data changes over time much more predictable (and powerful).
Does your editor let you manipulate the code as a lisp? The tree-based nature of the code allows for incredible automatic re-organisation of it, on the fly as you need to reshape it.
Have you used transducers yet? They let you specify the essence of a computation and apply it in different contexts - to a series of in-memory values, or values arriving over a network pipe, or any other source, without having to know in advance what that source is
But if these don’t appeal to you or you don’t see the benefits of them then maybe it isn’t for you - which is totally fine. Python can let you express this stuff too, albeit in clunkier ways at times and with a less pleasant refactoring experience. The python repl is also less powerful and not advocated for as a development tool in the same way Clojure’s is.
It really depends on your end-goal. If you’ve not been frustrated by the idioms Python gives you changing languages might feel a little pointless. I’ve used both and I’m far more productive in Clojure. It really rewards study and practice, and grows with you. Python is fine, but it’s a means to an end for me - get in, just get it done, try to remember the irregular syntax, weird build specification, get over white-space layout, use print debugging to get over the repl… it’s not my favourite but it’s perfectly usable.
Then there's performance. Clojure is usually within Java range and when it isn't interop is no problem. Python is slow as molasses, probably at least 10x slower if not more than anything running on the JVM with nothing to show for it.
For Machine Learning Python is fine because you're typically writing ~300 lines of glue code.
- Real immutability
- Persistent data structures with structural sharing
- A real Lisp REPL not a Python console
- 650 builtins to wrangle data in ways yo never imagined possible
- The JVM and JS platforms
- Rich Hickey
That's a pretty good deal I think. By contrast Python has crippled single statement lambdas, late binding footguns and weird scoping. No contest. Ruby is much better at what Python tries to be as it wasn't designed by a BDFL who dislikes functional programming. Python's popularity is the result of Google's adoption and a marketing exercise in academia. For quality of design Python ranks near the bottom.
[1]: https://jackrusher.com/strange-loop-2022/
As someone who writes more Python than Clojure these days, Python's limited lambdas are a regular source of frustration. Additionally, Clojure's first-class data structures are sorely missed in Python.
> 2. REPL-driven development!
The huge drawback IMHO that rarely gets discussed is the ability to change modules in Python's interactive interpreter (Clojure's analog is the namespace). For example, in the context of a web app, adding a new view in some views module, then swapping to the routes module and adding the adding a new route to wire up the view. Additionally, there's no built-in way to connect to the interpreter, as manually typing in a REPL is not the usual flow. To me this makes Python's interpreter unusable for anything but toy examples.
> 3. Macros!
Clojure is less macro-dependent than other lisps, but in most projects I use, there are one or two that really help clean things up. If you look to other modern languages that have macros (for example, Rust), I think the same idea applies.
- chaining together small functions to make more complex things (due to the lack of a pipe operator)
- immutable data structures (the built ins are mutable)
- working in a monadic context (option, result, etc)
Clojure can handle all of these.
Python list comprehensions are not very good compared to those in other languages.
Additionally there is the benefit of an expression orientated language, which is hard to grok at first.
The concise way of writing Clojure/Lisp, which is often praised as one of its benefit (shorter code!) to me often just made it harder to understand.
Also, coming from TypeScript, I was really missing the static typing - TDD was not a sufficient replacement for me, as I feel that again the main benefit of static typing is more easy understanding when reading other people's code.
Since you mentioned PG, here's a very good counter point given by Jonathan Blow to what he says, and a discussion between the two (rare to see on HN): https://news.ycombinator.com/item?id=21237636
So I'm sure as part of your learning you will have created a web app maybe a rest end point or nextJS, next I want you to go check out Clojure Electric take a look at some of the demos and try and replicate it in JavaScript with any framework in less code
If you're convinced of the potential for the language install clj-kondo, parinfer, paredit into your editor and never type directly into the repl
Unfortunately it's nearly impossible to learn Clojure without tooling support so find that Clojure plugin for your editor and don't ignore the other tooling before starting
As for functional programming, if your rebuttal is that python has list comprehensions, you still need to do some more digging into it. I suggest you read Peter Norvig's pytudes, he writes python in a functional way and uses both higher order functions (which are there, but really meh) and list comprehensions. They are not the same thing. Clojure also has immutable structures which is imo just as important for functional programming.
Not to say that python can't be used for it (pytudes really looks like art). For clojure maybe you can watch the parent of the dead series on YouTube (there's an ongoing reboot of the series). The repl workflow is so different from other languages that you really need to see people code in clojure live to understand it.
https://www.parens-of-the-dead.com/
https://github.com/norvig/pytudes
Just wanted to add a channel to this that I recently came across with a few videos about different REPL use. I also suggest seeing how other people use it, I keep picking up a few new tricks here and there by doing so.
Show me your REPL: https://www.youtube.com/@smyr-clj/videos
Clojure has immutable first data too, it can shield you from a lot of issues, especially when working with young devs. I still remember some python code some guy made. 3 files, 5 pages each, tons of loops over mutable dicts. Side effects everywhere. The actual logic fits in 50 lines of code with functional idioms.
All lisps features are now pushed into rare needs/researchy contexts, the mainstream absorbed a lot. See clojurescript electric to see an interesting DSL-y idea. And in a way, I consider django a half DSL (lots of classes are static descriptions assembled in a tree of faux-dataclasses.. it's a DSL without the name or ease).
Enjoy python, but keep an eye on other languages (be it clojure, sml, haskell, prolog, apl, perl6) it's always interesting.
I'd say that the value of learning a lisp-y language is that it is very different from mainstream languages (but you'll notice that modern languages have borrowed many features, sometimes in a strange way). Learning a lisp is good because it can change the way you think, not because it's some magic technological wand that will solve all your problems.
The REPL comment above, though, shows that you might not be developing in a very idiomatic way. Clojure is usually developed with an editor (emacs, but there are others like Conjure/nvim & Calva/vscode) that sends s-expressions to be evaluated by a separate process (the REPL). The expression's value is sent back and displayed in line with the code.
The key thing here is that instead of building your program all at once and running it as a whole, you build the program one expression at a time, and when you are ready you can evaluate the program as a whole. It's hard to pick up these habits if you are working in isolation, but it is a very different way to develop software, and is big reason people like lisp-y languages.
Many languages provide a 'REPL', but don't support this style of development, which is really what people who know are crowing about.
Except the small detail of having a mature set of JIT tooling (PyPy keeps striving for attention).
> Where else are you going to do your machine learning, for example?
Using any language with FFI to the same native libraries that Python uses.
Does Python have a good analogue for the threading macros (`->`, `->>`, etc)? (Genuine question)
Specifically: https://toolz.readthedocs.io/en/latest/api.html#toolz.functo...
On macros, they are not discouraged, it is just encouraged to use them only when needed. Lots of very useful libraries are based on them, and much of the core language is too.
I also think Clojure wins on other features. Being able to create a one file deployment that packages all of my dependencies (including Clojure) in to a single file. Performance and multi threading both give clojure another bump.
Deleted Comment
A good place to start would be implementing Rich Hickey’s ant colony demo in both Python and Clojure. https://youtu.be/dGVqrGmwOAw
Despite Lisp being one of the oldest popular languages, now almost 50 years, there must be a reason why it never become mainstream. Until Lisp language developers figure out these reasons and address them, Lisp and its cousins likely remain in academic niche.
Dead Comment
Those that do, are you excited about REBL? (If so, why?)
How do they like Datomic in 2023?
Do they miss regular RDMS like MySql and Postgres?
(Came to the comments hoping there would be more comments on Datomic, REBL, etc. But it just turned into a flame war between Python and Clojure of all things.
>Fogus has been mostly focusing on some new tooling derived from REBL and we are hopefully nearing a point of release on that and some additional supporting libs soon as well.
From third paragraph here: https://clojure.org/news/2023/03/27/deref
This is important because the core Clojure license is true open source vs REBL which had a semi closed license, so it’s always been a little difficult of a choice for many people.
A physical sub-pixel is red or green or blue. Mutually exclusive!
AFAICT, the name REBL is a play on “REPL” and “rebel”.
REBL let's you browse complex data structures and move around in them. In a REPL, printing a megabyte of JSON can be ... hard to read.
https://github.com/bhauman/rebel-readline
Deleted Comment
Dead Comment