It's interesting that the very things that attracted the author to Clojure was what kept me from moving to it from Python.
I enjoyed the syntax. Loved the immutability. However, I wasn't able to understand the structure of program data at a glance even when reading my own code. The reliance on lists and maps everywhere meant that the structure of data was encoded in the code of the functions that created it and sometimes you had to go several functions deep just to understand the bit you wanted.
In Python if I'm returning a tuple that's more than 2 or 3 elements long, I know that it's time for, at the very least, a namedtuple because I've had to deal with code in the past that has mysterious 5-tuples etc that just becomes too tiring to deal with.
To be clear, big collections in Python aren't a problem as long as the type of the contained data remains uniform.
I feel like people who come to Clojure forget the lessons that were known from the time of SICP that just because you can program using data, does not excuse not building up an abstraction tower.
If you have entities in your domain, presenting clean and encapsulated ways of interacting with them is a separate concern from navigating and modifying their underlying datastructure, which is an implementation detail.
IMO the "it's just data" benefits of Clojure are that a lot of the common patterns which might have felt like being macro-worthy in CL/Scheme are achievable using things like keywords, which leads to more uniform code (rather than ad-hoc project-specific macros).
My impression of Python is that it's a Fisher Price Little Tikes coupe with a few GE90 jet turbine hardpoints mounted on it.
It's a very simple language. Literally when things get made to be complex Guido says do it the simple way, because when unbreakable things break it's just that much harder to fix. This makes it very easy to debug, very easy to fix/patch, very easy to onboard new/junior developers in, and very easy to start using in production. It's literally a baby.
But man, you can do some crazy things in Python if you want. You can write C/C++ extensions sure. You can also use things like orchestration with `py4j` and `jpype` in order to execute IPC with a JVM dedicated to the Python process. In that sense all Python in your application becomes a request layer with the JVM or a binary acting as the data layer, and request layers don't require as much in performance because you only need to issue so many requests. Request layers may also need to change faster than data layers/pipelines, and in that Python's great because it's so flexible. Based on some performance testing our team did there's absolutely no reason to simply switch away from Python, though that may also be due to legacy reasons.
I'd like to stick to Python and maintain my Python proficiency going forward (though with Guido out as BFDL we'll have to see how the language evolves). I'd like to maybe add Rust or Elixir to my repertoire and see how they extend my capabilities in ways Python/C/C++ may not. But Python will always be my Swiss Army knife turned combat shovel. It gets the job done.
Are you implying Clojure is not simple? Have you ever watched Rich Hickey's "Simple made easy" talk? If you haven't, I highly recommend it. Disclaimer: It's not about Clojure.
I can, and do, appreciate opinions on languages themselves. But my decision to continue using Python over Clojure is much less about the language's syntax and more about the available libraries. How do Clojure web frameworks compare to Django/Flask? What would I use instead of Pandas for data analysis? Are there keras-like deep learning tools?
Switching languages based on a comparison of idiosyncrasies between the two seems like moving to a new city based solely on the weather: a valid consideration, but nowhere near sufficient.
Clojure generally has pretty good library support: the JVM has several high-quality web application servers: Jetty, Netty, Tomcat, Glassfish, etc. And, being a Lisp, Clojure can wrap these with a nice interface. The same is true in other areas: you have very nice access to the entire JVM ecosystem and really-well designed interop with the host language's concepts so, to a large degree, you never run into a situation where you can't do something because there isn't a good library for it: at work, we regularly use Kafka, Avro, Elasticsearch and several other major data systems and we mostly just use thin wrappers around the official Java implementations of the clients for these systems.
Similarly, when connecting to a database like Oracle, it's trivial to just use JDBC/etc. while, for example, my coworkers who are using Haskell generally have to write a Java gateway because there aren't well-tested clients for Haskell.
I agree. Within the data science community I often see the question of "R versus Python" and it always makes me think of the Old El Paso commercial: ¿por qué no los dos?
I know choosing the right tools for the task can have serious long-term implications on the project, team, or organization level, but individually I get the impression that people worry too much about which language is best when, in reality, many of them are perfectly suitable and appropriate.
Clojure works on the JVM so you have native access to all of the Java ecosystem. With that in mind I'd say the libraries are actually better for Clojure with the exception of data analysis. I don't think there's a language out there that has as many data libraries as Python (like Pandas).
When comparing programming languages / tech stacks, I am also more interested in the full picture (libraries, complexity, performance) than just differences in syntactic sugar. I use https://github.com/gengstrand/clojure-news-feed as a test bed for such evaluations. There, you will find almost feature identical microservices in clojure using ring with the jetty adaptor and python 3 on flask.
The clojure service was in 13 files with a total of 710 Lines of Code. The python service was in 33 files with a total of 1561 LoC.
I also have published load test results of these microservices at http://glennengstrand.info/software/performance/eks/gke where you will find the per minute average throughput for these two microservices to be about the same but the clojure version was about twice as slow as the python version.
Personal Opinion: Django is a nightmare to work with. It's too opinionated and a pain in the ass. However, I love Flask. I wouldn't be where I am today had I not found Flask in 2012/2013.
If you're looking for web technologies in Clojure, you'll find quite a few good ones. However, I say web technologies instead of frameworks because generally, the Clojure community prefers to compose libraries to suit their needs and not leverage an opinionated framework. However, if you'd like someone to do that composing for you, the Luminus web template is fantastic.
At least for me, it definitely factors in. Getting a new perspective on problems by using a language with a different toolbox (functional rather than OOP for example) can help with future problems. And it's just good fun to learn a new language just to challenge yourself a bit.
You're definitely right. I had a run in with PolyML in College and I was absolutely terrified of any functional language (nearly failed the class, in fact). Before deciding to switch from Python to Clojure, I had used Clojure briefly a few years before and hated it (was writing mostly Groovy at the time).
After some time to grow, I had started caring about different principles in the languages that I used. I had been ruined by mutable state too many times; I got tired of not knowing how to get the number of wheels on your instance of the car class, I got tired of so many things. Clojure was/is a wonderful reprieve from all of these things, but truth be told, I do still struggle with it from time to time. Or at least, it feels like I do.
I have considered multiple times switching from Python to other alternatives. However, I instantly discard any language with a Lisp-like syntax. I just cannot work with it. Being a Haskell hobbyist, I would like Python to be statically type and have better support for pure functional programming, but Python has the libraries that I need.
Every person that I've talked to that seemed to have a strong negative opinion about parens never used it. They just think they won't like it but wouldn't take the minimal amount of time to give it a try with something like paredit. I was also in this camp for a long time until I figured I would give it a serious try instead of disparaging something I had not used. You might consider that creating and editing code with balanced parenthesis doesn't actually require you to insert them manually when you have an editor that will always keep the code data-structure balanced and makes structural editing simple.
I'm not being facetious, here. I just can't imagine any reason one _couldn't_ work with it, once the syntax is learnt. There's nothing about lisp-like syntax that's inherently hard to learn.
I've programmed for 10 years in Clojure and have many regrets, but I've grown to just accept that Lisp syntax is correct. On day one you need to understand one thing. Years later, you need to understand one thing. And sure, in Clojure they happen to use three types of brackets for brevity but even that's optional. But other languages have dozens if not hundreds of little syntactical edge cases. I personally find that inconsistent mess repulsive.
"I instantly discard any language with a Lisp-like syntax. I just cannot work with it."
I feel the opposite. I avoid any language without a Lisp-like syntax, since its absence is a serious handicap which unnecessarily complicates code and makes it less readable.
I also much prefer the Lisp idiom of using meaningful function and variable names, vs the one-letter names and crypitic operators that are so common in Haskell, OCaml, and SML.
I haven't got much experience with Lisp, but I can imagine that, similarly to Python's significant indentation, it's a shallow weirdness that can be overcome easily after a little while. In both cases a little help from the editor will probably be needed.
Yeah, there are people who simply can't read Lisp syntax. Where I see structure and beauty, they see "murder of parens" (or whatever demeaning collective noun they use to describe it). I call them dyslisplexics.
Lately I've been playing with Coconut [1], a functional language that is a strict superset of Python 3. It transpires to Python and can use all of Python's libraries. I've been playing with it lately and quite like it.
Python's async support also seems to be getting better. There's a flask clone called Quart (http://pgjones.gitlab.io/quart/) and an async postgres client (https://github.com/MagicStack/asyncpg). It works very similar to JavaScript, with async and await keywords. I think it should provide speed and comfort especially if you're a regular JavaScript user.
If you allow me to compare my very limited experience with Python (hacking SublimeText plugins) to my rather extended experience writing Java or Ruby (i.e class-based languages that traditionally newline-&-deindent closing parens rather than aggregating them in a trailing tiger tail like in lisps) ...
... I would say writing programs in Clojure leads me to writing 10 to 20 times less code on average.
I recently rewrote 15000 lines of Java (several weeks worth of effort split in several dozen files) down to 500 Clojure lines (in one weekend and one single file).
Anyone else with that kind of experience ? To me this is a tremendous advantage and any argument for code readability is really just argumentation about reading code at a small scale (say one file) that unknowingly makes trade off about reading code at bigger scales (say the readability of a whole project).
> ...the “implied self parameter” on python methods turned me off.
If I had a nickel for every time I got the "TypeError: random_function() takes 1 positional argument but 2 were given" because I forget the "self" parameter I could buy myself a coffee. Probably a fancy one from the Starbucks even!
It's not implied, it's explicit in Python. you have to put it right there in the method signature! And it's obvious when python passes it in cause you used dot syntax!
Other languages have implied "this" or "self".
class LiterallyThere:
def method(self, foo):
"Literally explicit, self"
Dot operator means apply this method to thing left of dot by executing method with thing on left as first arg.
LiterallyThere.method('foo')
passes the class object LitterallyThere as the first arg
lt = LiterallyThere()
lt.method('foo')
passes the instance of the class object represented by lt as the first argument.
method(something, 'foo')
If you were able to reference method without a dot, you would have to supply two arguments cause method takes two arguments.
You literally, explicitly have to tell the interpreter what you are passing as first parameter and you method signature has to literally, explicitly accept that parameter.
I always thought this made sense: a method, considered as a property of a class isn’t yet bound to any particular instance while, considered as a property of an instance has an implicit parameter of the instance you’re currently operating on: languages like Java hide this “this” parameter from you by passing it automatically while python makes it explicit so you can form a better mental model of what’s going on
There are linters for these kinds of things that work with most editors. E.g. VSCode with pylint marks the method immediately, if you forget `self` or `cls`.
Willing to bet money the author switched to something else by 2017. For the overwhelming majority of developers Clojure is this tinker toy we fiddle with for 6 months to a year before getting bored and fed up with its limitations.
I don't have a horse in this race but I find it interesting that in my career I've seen a lot of bad code but the worst clusterfucks I've met where all in Clojure while the community seems to be chock full of purists and in general people that takes craftmanship seriously at least at face value.
Not sure if it's still a thing, but the slowness of starting the REPL was what kept me from moving to Clojure. Python is doing much better in that regard.
I switched from Python to Clojure (because abstractions), and then to Go (static types; efficiency) and then to Elixir (because work) and then to Haskell (no more lame types and stupid nil errors).
I feel like with Haskell I have basically achieved perfection, and I'm more prepared to work on the other languages if the situation calls for it.
[+] [-] hetman|7 years ago|reply
I enjoyed the syntax. Loved the immutability. However, I wasn't able to understand the structure of program data at a glance even when reading my own code. The reliance on lists and maps everywhere meant that the structure of data was encoded in the code of the functions that created it and sometimes you had to go several functions deep just to understand the bit you wanted.
In Python if I'm returning a tuple that's more than 2 or 3 elements long, I know that it's time for, at the very least, a namedtuple because I've had to deal with code in the past that has mysterious 5-tuples etc that just becomes too tiring to deal with.
To be clear, big collections in Python aren't a problem as long as the type of the contained data remains uniform.
[+] [-] yomly|7 years ago|reply
If you have entities in your domain, presenting clean and encapsulated ways of interacting with them is a separate concern from navigating and modifying their underlying datastructure, which is an implementation detail.
IMO the "it's just data" benefits of Clojure are that a lot of the common patterns which might have felt like being macro-worthy in CL/Scheme are achievable using things like keywords, which leads to more uniform code (rather than ad-hoc project-specific macros).
[+] [-] kevin_thibedeau|7 years ago|reply
[+] [-] panzerklein|7 years ago|reply
[+] [-] tarunkotia|7 years ago|reply
[+] [-] yingw787|7 years ago|reply
It's a very simple language. Literally when things get made to be complex Guido says do it the simple way, because when unbreakable things break it's just that much harder to fix. This makes it very easy to debug, very easy to fix/patch, very easy to onboard new/junior developers in, and very easy to start using in production. It's literally a baby.
But man, you can do some crazy things in Python if you want. You can write C/C++ extensions sure. You can also use things like orchestration with `py4j` and `jpype` in order to execute IPC with a JVM dedicated to the Python process. In that sense all Python in your application becomes a request layer with the JVM or a binary acting as the data layer, and request layers don't require as much in performance because you only need to issue so many requests. Request layers may also need to change faster than data layers/pipelines, and in that Python's great because it's so flexible. Based on some performance testing our team did there's absolutely no reason to simply switch away from Python, though that may also be due to legacy reasons.
I'd like to stick to Python and maintain my Python proficiency going forward (though with Guido out as BFDL we'll have to see how the language evolves). I'd like to maybe add Rust or Elixir to my repertoire and see how they extend my capabilities in ways Python/C/C++ may not. But Python will always be my Swiss Army knife turned combat shovel. It gets the job done.
[+] [-] iLemming|7 years ago|reply
[+] [-] Townley|7 years ago|reply
Switching languages based on a comparison of idiosyncrasies between the two seems like moving to a new city based solely on the weather: a valid consideration, but nowhere near sufficient.
[+] [-] fiddlerwoaroof|7 years ago|reply
Similarly, when connecting to a database like Oracle, it's trivial to just use JDBC/etc. while, for example, my coworkers who are using Haskell generally have to write a Java gateway because there aren't well-tested clients for Haskell.
[+] [-] o10449366|7 years ago|reply
I know choosing the right tools for the task can have serious long-term implications on the project, team, or organization level, but individually I get the impression that people worry too much about which language is best when, in reality, many of them are perfectly suitable and appropriate.
[+] [-] malvosenior|7 years ago|reply
[+] [-] gengstrand|7 years ago|reply
The clojure service was in 13 files with a total of 710 Lines of Code. The python service was in 33 files with a total of 1561 LoC.
I also have published load test results of these microservices at http://glennengstrand.info/software/performance/eks/gke where you will find the per minute average throughput for these two microservices to be about the same but the clojure version was about twice as slow as the python version.
[+] [-] souenzzo|7 years ago|reply
Flask -> pedestal/clojupture
Relay -> fulcro
Pandas -> clojure.core, specter
Keras -> mxnext/neanderthal
[+] [-] bradcypert|7 years ago|reply
Personal Opinion: Django is a nightmare to work with. It's too opinionated and a pain in the ass. However, I love Flask. I wouldn't be where I am today had I not found Flask in 2012/2013.
If you're looking for web technologies in Clojure, you'll find quite a few good ones. However, I say web technologies instead of frameworks because generally, the Clojure community prefers to compose libraries to suit their needs and not leverage an opinionated framework. However, if you'd like someone to do that composing for you, the Luminus web template is fantastic.
http://www.luminusweb.net/
[+] [-] Aeolun|7 years ago|reply
[+] [-] Insanity|7 years ago|reply
[+] [-] bradcypert|7 years ago|reply
You're definitely right. I had a run in with PolyML in College and I was absolutely terrified of any functional language (nearly failed the class, in fact). Before deciding to switch from Python to Clojure, I had used Clojure briefly a few years before and hated it (was writing mostly Groovy at the time).
After some time to grow, I had started caring about different principles in the languages that I used. I had been ruined by mutable state too many times; I got tired of not knowing how to get the number of wheels on your instance of the car class, I got tired of so many things. Clojure was/is a wonderful reprieve from all of these things, but truth be told, I do still struggle with it from time to time. Or at least, it feels like I do.
[+] [-] snrji|7 years ago|reply
[+] [-] jhhh|7 years ago|reply
[+] [-] omginternets|7 years ago|reply
Can't or won't?
I'm not being facetious, here. I just can't imagine any reason one _couldn't_ work with it, once the syntax is learnt. There's nothing about lisp-like syntax that's inherently hard to learn.
Why is lisp special?
[+] [-] thom|7 years ago|reply
[+] [-] pmoriarty|7 years ago|reply
I feel the opposite. I avoid any language without a Lisp-like syntax, since its absence is a serious handicap which unnecessarily complicates code and makes it less readable.
I also much prefer the Lisp idiom of using meaningful function and variable names, vs the one-letter names and crypitic operators that are so common in Haskell, OCaml, and SML.
[+] [-] moomin|7 years ago|reply
Indeed, if you really want fun, try Hackett: a Haskell variant implemented in and for Scheme.
[+] [-] dorkusmagnus|7 years ago|reply
[+] [-] rhizome31|7 years ago|reply
[+] [-] swlkr|7 years ago|reply
You still get the great “execute this block of code in the repl” with the parens too.
[+] [-] pletnes|7 years ago|reply
[+] [-] iLemming|7 years ago|reply
[+] [-] bradcypert|7 years ago|reply
It's really not that bad! Here are some insights into the parens!
1. I've converted Java code over to Clojure and found that it has less parens per file.
2. They're still there, they're just in a different place. `System.out.println("")` vs `(println "")`
3. There are some great tools to help with the Parens. If you're using Intellij, Pareninfer and Rainbow parens are two extremely helpful tools.
[+] [-] coliveira|7 years ago|reply
[+] [-] endgame|7 years ago|reply
[+] [-] garyrob|7 years ago|reply
[1] http://coconut-lang.org
[+] [-] black-tea|7 years ago|reply
[+] [-] o10449366|7 years ago|reply
[+] [-] benatkin|7 years ago|reply
[+] [-] Scarbutt|7 years ago|reply
[+] [-] bradcypert|7 years ago|reply
My opinion has not change as I've never looked back ;)
I've found a fun little home in the JVM, but I'll definitely check out data classes in Python! That seems pretty cool :)
[+] [-] GorgeRonde|7 years ago|reply
... I would say writing programs in Clojure leads me to writing 10 to 20 times less code on average.
I recently rewrote 15000 lines of Java (several weeks worth of effort split in several dozen files) down to 500 Clojure lines (in one weekend and one single file).
Anyone else with that kind of experience ? To me this is a tremendous advantage and any argument for code readability is really just argumentation about reading code at a small scale (say one file) that unknowingly makes trade off about reading code at bigger scales (say the readability of a whole project).
[+] [-] UncleEntity|7 years ago|reply
If I had a nickel for every time I got the "TypeError: random_function() takes 1 positional argument but 2 were given" because I forget the "self" parameter I could buy myself a coffee. Probably a fancy one from the Starbucks even!
[+] [-] njharman|7 years ago|reply
Other languages have implied "this" or "self".
Dot operator means apply this method to thing left of dot by executing method with thing on left as first arg.LiterallyThere.method('foo')
passes the class object LitterallyThere as the first arg
lt = LiterallyThere()
lt.method('foo')
passes the instance of the class object represented by lt as the first argument.
method(something, 'foo')
If you were able to reference method without a dot, you would have to supply two arguments cause method takes two arguments.
You literally, explicitly have to tell the interpreter what you are passing as first parameter and you method signature has to literally, explicitly accept that parameter.
[+] [-] fiddlerwoaroof|7 years ago|reply
[+] [-] Rotareti|7 years ago|reply
[+] [-] doktrin|7 years ago|reply
[+] [-] luckydata|7 years ago|reply
¯\_(ツ)_/¯
[+] [-] amelius|7 years ago|reply
[+] [-] anentropic|7 years ago|reply
it's `setup.py`
[+] [-] unknown|7 years ago|reply
[deleted]
[+] [-] sridca|7 years ago|reply
I feel like with Haskell I have basically achieved perfection, and I'm more prepared to work on the other languages if the situation calls for it.
[+] [-] fopen64|7 years ago|reply
[deleted]
[+] [-] wyclif|7 years ago|reply