'(Clojure Annoyances)
Audience: Clojure beginners
“You have to be quite heavily invested in someone to do them the honour of telling them you’re annoyed with them.” ― Alain de Botton
Every language has warts. This is not the first wart piece written on Clojure, but it’s my unique take on it. There are some workarounds, but these will bite newbies. Despite these minor annoyances, I still find Clojure to be the best environment to work in for many years to come.
Memory hogging
That’s a Raspberry Pi in his mouth. It’s being devoured.
Every time this is brought up there are arguments that Clojure and the JVM alone
don’t use too much memory. But once lein
is starting an nREPL for a
non-trivial project, you’ll want to have a 16+ GB machine. The situation would
be even worse if you use a heavy IDE (like IntelliJ or Eclipse).
I’m still sometimes clumsy with my setup, and may have a REPL going that’s not
connected to Vim, plus a lein run
server running. And then another for
generating this blog (that one has some leak that gets it up to 5 GB after a few
days!). Maybe another for testing and working through 4clojure. So if you’re not
careful, you’ll want to limit yourself to running one project at a time.
All this can make Clojure a non-starter for students with minimal systems, like older Linux laptops or Raspberry Pis.
Remedies: https://github.com/technomancy/leiningen/wiki/Faster, light/smart editors
Slow startup
Clojure starts up quickly (relative to lein, anyway). But the full lein
environment is taking me 17+ seconds in a default Luminus project.
Clojure itself is super fast for a lot of things…. once it’s started.
Remedies: Trampoline, Drip
Lots of parentheses
These can drive a newbie crazy. But once you learn to paredit them, they’re quite a boon for moving code around. They’re also pretty easy to auto-add and auto-balance, and even auto-color.
Remedies: paredit, sexp, rainbow parentheses
Deal with Java
Process trees cluttered with really long invocations.
This happens with a lot of other environments, too, though. I see it with Erlang when running RabbitMQ; with Rails running Passenger; with MySQL; etc.
Remedies: tree view, live with it, forget *top and use real monitoring tools
Awful backtraces
I actually don’t see these very often. I’m not sure if it’s due to
clj-stacktrace
being everpresent in my setup.
Remedies: small fonts, scrolling
Not always expressive
Heavy setup
In Racket
Everyone uses Emacs
…and maybe you don’t. But that’s okay. Many are also having success with Vim, LightTable, and Cursive.
You can watch guns in this video doing some cool things: https://vimeo.com/80650659https://vimeo.com/80650659
Docstrings require an extra line
def fetch(dog):
"Get dog to grab my slippers."
dog.walk_to_bedroom() ...
(defn fetch
"Get dog to grab my slippers."
[dog]
(walk-to-bedroom ...) ...)
(defn fetch [dog]
"Get dog to grab my slippers."
(walk-to-bedroom ...) ...)
This, of course, is due to multiple arity support, but still annoying. So I find myself resorting to:
;; Get dog to grab my slippers.
(defn fetch [dog]
(walk-to-bedroom ...) ...)
But Clojure is still the best
The Criteria: Only three really in the race
I’ve grown persnickety after many years working with less satisfying environments, and now I value comfortable workflow above most things. This has brought me to only considering a few that have hope for joyful programming. They are Clojure, Racket, and OCaml. (Elm and LiveScript get honorable mentions as great languages.)
-
expressive, succinct
-
simple
-
functional (and thus parallelizable)
-
fast and light (Clojure almost doesn’t make the cut here)
Considerations that are secondary also, unfortunately, have strong impact:
-
jobs available
-
projects with many eyeballs
-
widely adopted in usage
-
tutorials, books, screencasts, discussions
In the end, Racket and OCaml both suffer from having communities that are too small, tools that are not widely enough adopted, projects without enough eyeballs, and tutorials not yet written. As much as I (and you) should work on addressing those shortcomings, most of us have other practical things presently pressing harder.
So that leaves us with Clojure.
(It’s not that I haven’t considered most of the up-and-coming languages that get a lot of attention. They just don’t satisfy the above constraints. So, I’m left not really considering: Scala, Elixir, Rust, Go, Haskell.)
Summary of Why Clojure Wins
(Note: shown above is vim using the “conceal” feature for functions like partition, map, apply, etc. You either love or hate this.)
-
Aesthetics
-
code density
-
beautiful rainbow parens (hooks for moving code)
-
functional:
map
,filter
,reduce
-
-
Paredit/Sexp: parentheses become hooks for moving code
-
Trivial parallelism (sometimes, via
pmap
) -
Isomorphic possibilities: server (web frameworks) and client (reagent, om). You’re probably not going to be a great developer in both JavaScript and some other language on the back end (Ruby, Python, Java), so why not just be great in Clojure/Script?
-
Crazy REPL abilities
-
Many companies are invested
-
A better way to use Java libs
-
Lein is an all-in-one (cf. rails, gem, bundle, rake)
-
but also boot
-
-
Many learning resources (books, podcasts, screencasts, newletters, discussions)
-
A simple language mostly grokkable in a day (by experienced programmers with some functional knowledge)
-
Many tools (plus anything from java)
-
Great data structures
-
Functional code (referentially transparent) is most testable
-
All the fancy big data tools are now java (spark, storm, flink, hadoop…)
-
Macros (there’s even a book on them)
-
A style guide whose perfect sensibility says a lot
-
A debugger inside emacs!