My view on Elixir and Clojure

Elixir and Clojure are two uprising and fun functional languages. As you know, I talked about both of them in the article on the most promising languages of 2016, and, in fact, they are the only real functional languages I mentioned in there.

At the time, I didn’t really explore these two languages in deep, and in fact, I think I was a bit too hard on Clojure. During this half year, I had the opportunity to go deeper in Clojure and my opinion on the languages increased accordingly. Moreover, Clojure 1.8 came out just a month later with some nice improvements and the upcoming Clojure 1.9 (with the introduction of the clojure.spec) seems to push the bar even further. So, yeah, I was wrong on a big point: Clojure is advancing quite fast.

However, even if Clojure is a more established language, I preferred Elixir in the list as the most promising language. Well, after everything I said and after this half year of experience, I have to say that I will still put Elixir on top of Clojure again. And now, I will explain why.

What they share

Elixir and Clojure share a lot. They are both non-pure functional languages running on a Virtual Machine. They are both built on the shoulder of a giant collection of libraries (for Clojure is Java, for Elixir is Erlang). They are both focused on high concurrency. They are both dynamically typed. They are both quite young. They are tackling the same use cases.

As you see, they are very similar in many ways and it is natural to put one against the other. In some sense, they are rival.

Clojure’s Upsides

If they are so similar, why do you prefer Elixir? Before that, I need to clarify something: I don’t have any real-world big project with both languages. Therefore, take this with a grain of salt.

There are some aspects that I really love of Clojure. First, I like that Clojure is a modern lisp implementation. While Elixir syntax is heavily Ruby-inspired (a big pro if you came from Ruby), Clojure has the timeless elegance of Lisp. This is very subjective, I know. Also because it’s hard to say that, for instance , Clojure’s list comprehension is nicer than Elixir’s one.

Clojure:

Elixir:

But, you know. Lisp has some strange kind of beauty for me.

The second upside of Clojure is the Java Virtual Machine. Both JVM and BEAM (the Erlang Virtual Machine) are magnificent pieces of software. But the JVM is slightly faster and it definitely has a larger diffusion (that means, more people are testing the JVM and so it is more optimized/bug-free, in theory). This also means that Clojure can, again, in theory, work on Android (almost) natively. Moreover, you can use every enterprise approved tools of the JVM. Another big score.

Clojure has also a bigger community at the moment. That is always a good upside.

But other that these points,  I don’t really know why I should prefer Clojure over Elixir.

Elixir’s Upsides (Clojure’s Downsides)

There are many points for which I like to play with Elixir more than Clojure. I will focus on three of them.

First, the tools. I find Leinigen a bit bloated respect to Mix. Mix is faster, lighter and integrated with Elixir. Lein is not. I find Lein a bit slow, because is in Clojure and Clojure it is not a really good choice for command line tools.

This brings on the table the second point: startup time. Clojure is completely unpractical for quick command line scripts. This is not a big deal for webservers and other “always run” applications. However, I write mostly command line tools and this Clojure problem completely force me to avoid Clojure in my daily job. It is a shame.

Finally, the third and most important point: the error messages and the Java layer. The confusing error messages in Clojure are a common complaint. The main problem is that these errors are, mostly, Java errors. In other words, you speak Clojure and the compiler (or the runtime) speak Java.

This is an example. The Clojure error starts with java.lang. This error is referred to a wrong type passed to a function, but the error is in Java and talks about PersistenVector. Other errors are even more confusing. Plus: the stack trace is the Java stack trace. And it is not easy to map that to Clojure’s calls.

In my opinion, in Clojure, the Java layer pokes the Clojure layer way more than it should. Another example is that Clojure require to access the Java standard library in many cases. The problem with this is that Java functions and Clojure functions are not interchangable. For instance you can do

But you can not do

You need to wrap the Java function into a Clojure function explicitly in this way

I don’t find this particularly elegant.

Conclusions

Because Elixir shares most of the strong point of Clojure and none of the weak point, I think that in the long run Elixir is a better bet. Obviously, this can change depending on how the two communities will develop their language. However, right now, I’m really enjoying Elixir and I almost dropped Clojure. It was a pleasant discovery.

I cannot wait to see if in the future Clojure will steal the Elixir place in my personal ranking! :)

  • Alex Miller

    Planck http://planck-repl.org/ (recently ported to Linux) can be used to make fast command line scripts with ClojureScript. Boot is also a very nice build tool with a much different mindset than Leiningen – it rewards the time you spend learning its model.

    You mentioned clojure.spec. One of the features of spec is the ability to define a function spec, instrument the function, and have its arguments checked against the argument spec. Once Clojure core has been spec’ed, it will be possible to instrument core (and your own libs) at the REPL and see better error messages from both syntaxy macros (checked at compile time with a tie back to the invalid source, not the guts of the macro) and from Clojure functions before they get to the Java layer. The messages themselves will be in terms of specs, which are built from Clojure predicates. So stay tuned in Clojure 1.9 for things to improve here.

    Regarding the .javaFunction example, you can also use clojure.core/memfn to turn Java methods into Clojure functions.

    • I write these articles to receive this kind of comments. :) I know that the issues I mentioned are shared by many developers and, in fact, I’m happy that there are so many projects that try to address them!

      I didn’t know Planck (even because I mostly work on Windows) and I will try clojure.core/memfn to see if it fits well in the code. But, for sure, I’m waiting Clojure 1.9! As I said, I have this irrational love for Lisp-like languages. I’m totally tuned for advancement in Clojure!

      Thanks for sharing your comment!