Skip to content

Clojure

Dávid Szakállas edited this page Aug 1, 2017 · 3 revisions

Clojure

tldr; LISP on JVM

Clojure is a dynamic, general-purpose programming language, combining the approachability and interactive development of a scripting language with an efficient and robust infrastructure for multithreaded programming. Clojure is a compiled language, yet remains completely dynamic – every feature supported by Clojure is supported at runtime. Clojure provides easy access to the Java frameworks, with optional type hints and type inference, to ensure that calls to Java can avoid reflection.

Where to get help?

Community Docs: Much better than the official, has examples.

Reference: Useful, advanced documentation written by core contributors.

API Docs: Just the exported navigable API docs.

StackOverflow

Creating a project

Don't use Ant, Gradle or Maven. Use Leiningen.

Using an IDE

IntelliJ + Clojure = ❤️

There is a Clojure plugin for IntelliJ IDEA, which will give you the best experience if you like IDEs, and don't want to use Emacs. Proprietary, free for non-commercial use, acquire a license from their site: https://cursive-ide.com/

Structural editing

An absolute must have. Auto-balances parentheses on insertion and does other nice stuff making editing LISP fun.

Setting up in Cursive

Search for Structural editing in Settings to enable it. I use the ParEdit style. Works with IdeaVim, but you'll need to remap some stuff.

Structural editing 101

Move Down/Up => exchange form under caret with next/previous form

Slurp Left/Right => extend surrounding parentheses to include next form to the left/right

Barf Left/Right => shrink surrounding parentheses to exclude leftmost/rightmost form

Raise => replace surrounding parentheses with form under caret

Kill Sexp => delete form under caret

Kill => delete everything to the right of caret until closing brace

Split => split surrounding parentheses into two at caret

Join => join preceding parentheses with parentheses under cursor

Code style

tldr; Using Cursive's Reformat code action will give you a pretty good formatting. Use your brain to learn the style.

LISP code is indented differently than C-like languages. Clear your mind, don't try to apply rules learned there.

Indenting

Opening brace should be on the same line as the first form in it. Closing brace should be on the same line as the last form in it.

✅ DO

((((good)
    (good)
    (good))))

❌ DON'T

(
  (
    (
      (bad))))

((((bad)
    )
  )
)

You may move the second or later forms onto a new line. The indent depends on the opening parenthesis' position. Add 2 spaces to that if you move the second form, make it line up with the second if that remains on the first line:

✅ DO

(this (is (a
            (good (way)   ; second is on new line so I added 2 spaces
                  (hur-)  ; second is on the first line, third lined up
                  (ray)))))

❌ DON'T

(this (is (a
 (bad
 (way)
 (may)
 (day)))))

Commenting

You are encouraged to use multiple ;s to signify how mature that comment is. Of course the most important stuff should be in docstrings. For less important or sound stuff:

  • ;; when a comment is near doc level. Documentation for single functions that extends beyond the doc string (e.g. an explanation of the algorithm within the function)
  • ; In-line comments possibly on a single line, and possibly tailing a line of code

Using nREPL

Use the REPL. Super fast, and you get immediate feedback.

Cursive IDE

You should create a REPL for your project then Run REPL for MyProject. You'll have a lot of convenience actions. My favourites are:

  • Send form under caret to REPL
  • Send top form to REPL
  • Load file in REPL
  • Run tests in namespace in REPL
  • Run test under caret in REPL
  • Re-run last test action in REPL

Note: when you send a form to the REPL, its namespace is retained. If that namespace isn't loaded yet in the REPL, you won't have anything it requires, not even clojure.core (most likely it uses in-ns) resulting in strange errors such as that defn is unbound and such. So either send the whole file first, so you get the namespace declaration, or you have an option in Settings to set the form's namespace to the current namespace in the REPL when it is sent.

Linting

Clojure is a dynamic language. Use the Eastwood lint tool to prevent some common errors and unidiomatic code.

Clone this wiki locally