December 3, 2016 clojure

'(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.

title

Memory hogging

memhog

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.

Slow startup

slow start

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

parens

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

htop

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

stacktrace

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

py vs pi

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

Python supports this style of coding:
def fetch(dog):
    "Get dog to grab my slippers."
    dog.walk_to_bedroom() ...
In Clojure, we have to write:
(defn fetch
  "Get dog to grab my slippers."
  [dog]
  (walk-to-bedroom ...) ...)
But it would be much nicer to write:
(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

trinity

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

pretty2

(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!