Calling it quits without parentheses

aurellem

Written by:

Robert McIntyre & Dylan Holmes

Is it possible to make a quit command for Clojure such that simply typing the word quit at an REPL exits the REPL? An intuitive quit command would be especially useful for people new to Lisp syntax or the REPL; the challenge is to make a genuine Clojure command that executes without being called with parentheses. We found three solutions.

1 By modifying toString

(in-ns 'abomination.no-parens)
(gen-class :name abomination.no-parens.Quit
           :prefix quit-)

(defn quit-toString
  [this]
  (System/exit 0))


(defvar quit (abomination.no-parens.Quit.)
  "a sneaky way to support a `quit` command")

When you type any variable at the REPL, the REPL attempts to print it as a nicely-formatted string by calling its toString method. Our trick is to define a class with a toString method that exits the REPL; this trick ensures that any variable of that class will close the REPL when the REPL attempts to print it.

First, we use gen-class to make a new class named Quit; in that same line, we use :prefix to establish the convention that any function named quit-[something] will be adopted as the [something] method for the newly-defined Quit class. We use this convention to write our own toString method for Quit.

Next, we define a suitable toString method for the Quit class so that attempting to print an instance of the Quit class has the effect of closing the REPL. We do this by defining a function quit-toString which closes the REPL; by the convention established above, the Quit class automatically adopts quit-toString as its toString method.

Finally, we use defvar to create an instance of the Quit class; we name this instance quit. Now when you type quit into the REPL, the REPL executes the toString method of the Quit class, exiting the REPL instead of returning a string.

(binding [*compile-path* "/home/r/proj/abomination/classes"]
  (compile 'abomination.no-parens))
abomination.no-parens

2 By wrapping the command in a lazy sequence

(in-ns 'abomination.no-parens)
(defvar quit* (lazy-seq :the-great-bringer-of-death! (System/exit 0))
  "the first time it's evaulated it will kill the JVM")

3 By delay-ing the command

(in-ns 'abomination.no-parens)
(defvar quit** (delay (System/exit 0))
  "when this is evaulated at the REPL, it will exit the JVM.")

The same thing, accomplished in a much more elegant and clojureish way.

And death i think is no parenthesis —E. E. Cummings

Author: Robert McIntyre & Dylan Holmes

Created: 2015-03-02 Mon 15:43

Emacs 24.4.1 (Org mode 8.3beta)

Validate