What’s your opinion on Elixir vs. Clojure?
[warning, a bit ranty]
Let’s put it this way:
I’ve been doing Clojure as a hobbiest for about four years now, and learning Elixir at a beginner level right now, and I already prefer Elixir over Clojure.
- it’s a modern lisp
- the JVM platform is fast
- the language design is generally well thought out
- the “java layer” pokes through far too much, and unlike Elixir/Erlang the underlying Java idioms do not interact well with the functional-programming paradigm of clojure.
- documentation is pretty bad, and remains bad after years of badness (Elixir docs, even for community libs, are much better)
- as a side-effect of poor documentation: there’s often not a coherent story on “how to achieve $FOO” with Clojure. My most recent example was trying to figure out how to build pervasively-non-blocking and highly parallel http services in Clojure. I’m sure it can be done, but it’s very hard to figure out what will work.
- the build tool (leiningen) kinda sucks
- JVM startup time is torturous, by comparison iex/elixir starts almost instantly
And perhaps the biggest problem I’ve found: the core Clojure community is made up mostly of “90’s Java Guys” who wanted to work with a more sane language on the JVM. The rest of the community is FP enthusiasts who aren’t particularly invested in the JVM. In my opinion the first group end up dominating the culture too much. As a result of this, making anything bigger than a toy example app in Clojure involves getting your hands dirty with awful Java libraries. One minute you’re happily coding along in Functional Land, the next you’re digging around in the OOP, mutable-state muck of Java Land again. (see: https://twitter.com/shanekilkelly/status/703297846401957889).
This is a decent value proposition if you’re already financially/professionally/emotionally invested in Java, but for the rest of us it’s a painful experience best avoided.
Elixir, by comparison, doesn’t seem to suffer from the same impedance-mismatch with it’s host platform, which makes me a lot happier instantaneously. That and the fact Elixir has a coherent narrative when it comes to scalable computing, it’s looking like I’ll be investing more of my time in Elixir than Clojure.
EDIT: I decided this post was a bit too negative, so I’ll expand on some of the positive aspects of Elixir, from my point of view.
- very good documentation and on-boarding material (especially considering the size of the community)
- a better approach to namespacing/modules (clojure chucks a huge number of functions into the global namespace, while Elixir prefers to put ‘default’ functions in modules like Enum)
- a coherent vision for massively parallel and distributed computing and the multi-core future
- the Elixir devs and community seem to really care about code ergonomics
- the BEAM is an awesome piece of technology
- mix, and the general ecosystem of tools around Elixir, seem very nice and pleasant to work with
well this is more of rant than an actual comparison perhaps you should do your research before you do a posting, I myself a long time erlang programmer and I am also heavily invested in clojure/jvm in fact I have taught clojure to a decent size group of people.
As a result of this, making anything bigger than a toy example app in Clojure involves getting your hands dirty with awful Java libraries. One minute you’re happily coding along in Functional Land, the next you’re digging around in the OOP, mutable-state muck of Java Land again.
The above statement you made is not completely true if you pull in java library you are not writing java code you are actually calling java code in your clojure code I for one never written a line of java code while doing clojure.
And for the record there are companies I mean large companies using clojure for production not for toy projects.
He has not written, that one writes Java, but one has to deal with Java, and the way Java handles things, especially mutability.
But to be honest, this problem does appear in about every functional language which has an FFI into other languages.
@NobbZ, precisely. I find the bridge between Clojure and Java unpleasant to deal with. Even when we’re still writing Clojure we are forced to handle Java classes and objects with mutable state, which doesn’t mesh well with the rest of the Clojure program.
I’ve been doing Clojure for about four years now, so I think I’ve got enough experience to pass comment. However, I do acknowledge that this is just a personal opinion, there are plenty of Clojure devs who don’t mind the Java layer poking through at times.
But to be honest, this problem does appear in about every functional language which has an FFI into other languages.
Agreed. However I think Elixir has an advantage here, as it’s underlying platform is also a functional language, so there is less/no friction when the “Erlang layer” pokes through in your Elixir programs.
Even Erlang and Elixir are vulnerable to this through the concepts of ports. But since a semi-mutability is already there through state-holding processes, we don’t even recognize it.
Not quite as ports make the outside world look like a “process”. You communicate with it using messages as you would with any other erlang/elixir process. You are even linked to it. In this sense interacting with the outside world through ports is very clean, or at least very erlangy/elixiry.
And exactly that was what I meant
When calling an API that extracts some value from an opaque type, we don’t care if this value is extracted/returned just by patternmatching a tuple, fetching some state from another process or even from the “outside world” via ports. And since the type is opaque and we are all well behaving programmers, we don’t even care if we pass a tuple, a pid or something else around.
We are aware though that some function called with the same set of data may return different values on multiple calls. Try to make this understandable and comfortable to a Haskeller without using the “M” word
I found interesting article about Clojure Beyond Clojure Prelude. Do you think that Elixr can have the same problem?
Perhaps I’m wrong but my common sense tell me: If Erlang does probably Elixir will, otherwise I don’t think so.
Interesting article + good question. There are at least some discussions on typed/dynamic on this forum.
Another one (just on elixir vs clojure): https://www.reddit.com/r/Clojure/comments/5q2gmi/convince_me_to_use_clojure_over_elixir
Do you have any public code as a result of this effort? I would be curious to see what that looked like in clojure
Sorry to bump this older thread but I’ve been watching some of Rich Hickey’s videos and am a fan of his methodologies/philosophy so would like to learn Clojure in addition to Elixir. Do any programmers here with experience in both languages have any words of wisdom to share that hasn’t been covered in this thread yet?
Thanks in advance,
I was paid to work in Clojure for about 9 months, and now I’ve been paid to work in Elixir for 10 months. Here’s a few points to consider.
Syntax: Do you love to be hands on with the lisp AST? I tried really hard to like it, but I found it hard to skim unfamiliar Clojure code and get a high-level gist of what’s going on. I really had to read it carefully statement by statement to understand it because it lacks higher level syntactic signposts. Elixir offers those signposts, plus a macro system that is just as powerful. The only tradeoff is that Elixir macros are not as “natural” because it’s not fully homoiconic. I’m fine with that. Others aren’t.
Built in Libraries: I found Clojure to have a very broad standard library. There are many specialized higher-order-functions for what seem like rare situations to me. If you know the library well, you can probably use one of these to create all sorts of elegant one liners – and make it harder for the maintenance programmer to reason about. Elixir, in contrast, says “no” to a lot of proposals to add things to the standard library especially when they can be expressed in 2 or 3 lines of existing functions.
The VM/ecosystem: JVM has a larger set of libraries. It also lacks the memory isolation to do proper supervision/fault-tolerance the BEAM can do. Interacting with Java libraries from Clojure was more awkward because of the imperative/functional mismatch than interacting with Erlang libraries from Elixir, which are both functional/immutable.
In my opinion Clojure is a choice that makes sense if you are already locked into the JVM ecosystem by legacy decision making. So if you personally don’t already have experience in that area (e.g. Java development) and this is primarily about a personal experience and getting into the same kind of mindset I’d look into Racket instead.
- Racket Sucks, Don’t Try It (sarcasm)
- Things I already dislike about Python
- Not liking Python any better now
- Why Racket? Why LISP?
- Why John Carmack thinks Racket is aces for beginning programmers
Though not everybody agrees:
“Power” is hard to quantify, but I would re-frame it to say Lisp offers democratic macros that allow you to do anything you’ve previously seen in the language, whereas the signposts you mention specifically block off certain syntax behind the wall of the compiler. If the compiler has a strict and simple scheme for reading forms it democratizes syntax to the point where everything that was accessible to the creators is syntactically accessible to you and you’re allowed to build anything. There are forms you simply can’t use in a system where certain keywords have staked claims to them.
In that sense I think a keyword based syntax with these conceptual signposts limits the user and personally I value the other side of that much more highly than I value the signposts. They’re “Keep off!”/“Private property!” signs to me, more than signposts, I guess. I probably sound like a broken record, but I think the freedom offered by Lisp forms and reading scheme is something that is strictly better than the alternative.
I agree with your statement. I meant “power” as able to achieve the same range of behavior of the code, not about complete freedom of syntactical choices. Lisps definitely offer more freedom of syntactic expression in their macros.
I completely understand your point of view. I’ve heard it before and I’ve wanted to adopt it myself, but once I was honest with myself, I couldn’t. As an analogy I compare it to music. Some musicians want freedom from constraints about musical forms and something like free jazz is just right for them. Other musicians find that constraints fuel their creativity, and blues is a great genre for them.
I prefer to listen to blues and I prefer to code in a language with constraints. I’m not trying to change anyone’s opinion on the topic, but I want my biases to be clear so the reader can factor that in while reading my post.
I think @gregvaughn hits the nail on the head quite accurately WRT to syntax — Elixir gives you constraints and a limited way to break out, Clojure/LISP gives you freedom to do whatever you damn please, but in return it means that code is harder to skim.
In practice, you have to learn about your host anyway — if you plan to design and ship a production application, it matters if you are going to learn the intricacies of the JVM or BEAM or Node, and you have to play to their advantages. If not: square peg, round hole.
Finally, Clojure is a practical language — you can use mutable data structures if you want, you can create a Java GUI, you can depend on all the JVM infrastructure for tracing, profiling etc. You can ship your applications as a single JAR file that can be run with just a JRE installation. You can tweak the JVM to suit your application’s needs.
For me Clojure was a nice way to get into the mind of Rich Hickey, and it was a very nice learning experience. I don’t know if I will use it on production in the near future because it’s a harder sell than Elixir to most companies.