Getting to REPL

Suppose you want to try out Clojure, but don’t want to spent a lot of time setting up a project.

You just want to fire up the REPL and start playing with code.

Also you want to include other Clojure libraries dynamically on a whim. You don’t want to declare all of them first, or restart your REPL every time you think of a new library to pull in.

These steps will show you how to do this.

Boot-clj

First we are going to install boot-clj. Boot is similar to Lein with the difference that it lets you define your builds in Clojure dynamically.

Install boot-clj.

brew install boot-clj

Start boot repl.

boot repl

Test the REPL.

(println "Hello, world!!")

At this point the REPL should work. You can play with all the functions that ship with Clojure.

Adding Dependencies

For most interesting applications you want to pull in dependencies from mvnrepository or from clojars. Clojure core just isn’t enough.

Here is how to pull in 3rd party dependencies.

We are going to define a function called deps that will give us the ability to dynamically pull in dependencies from mvnrepository or clojars.

Paste this into your REPL.

; Define deps to pull in dependencies dynamically
(defn deps [new-deps]
  (merge-env! :dependencies new-deps))

Testing With CPrint

Lets test this using cprint, which is a color pretty printing function.

To use cprint we are going to pull in lein-cprint version 1.2.0. You can get the dependency name and version from mvnrepository or clojars.

; Here is how to pull in the dependency 
(deps '[[lein-cprint "1.2.0"]])

To use a function in the dependency we can either use use or requires. This will pull it into our current namespace.

; `use` imports cprint directly into our namespace
(use 'leiningen.cprint)
(cprint (range 10))

; `require` imports cprint as cp/cprint in our namespace
(require '[leiningen.cprint :as cp])
(cp/cprint (range 10))

REPL History

Now after hacking for a bit you will want to page through your REPL history.

To view the REPL history look at .nrepl-history in the directory where you started boot repl.

cat .nrepl-history

Loading Scripts

You can copy the history into a file, clean it up, and then refactor it into an elegant script defining functions.

Next time you start a session you want to load the script file you created. Here is how to load a script file into the REPL.

(load-file "myscript.clj")

This should give you a good starting point in how to use the REPL to interactively develop Clojure programs without getting bogged down in setting up a project.

REPL in Production

Now at this point you might say, “This is a great way to goof around in Clojure, but to put a system into production we have to put on a serious face and give up the joys of the REPL.”

Not necessarily. I run production servers with a Boot REPL. You can too. The REPL is a very powerful shell that lets you call and change parts of your Clojure program on the fly. It’s like doing engine repairs on a plane in flight.

Using the REPL you inspect and debug errors as they happen. You can dynamically redefine functions. And most importantly you can retain the playful REPL mindset in production.

Clojure Script Files

Can I run my Clojure scripts like I do with my Python, Ruby, Perl, and Bash scripts?

Yes you can. You can run your scripts directly using this shebang line #!/usr/bin/env boot on top of your script file.

Save this into hello.clj and try it out.

#!/usr/bin/env boot
(println "Hello world!")

This turns Clojure into a scripting language much like Python, Ruby, Perl, or Bash.

Faster Startup Time

If you want to speed up your startup time you can pass JVM flags into boot using BOOT_JVM_OPTIONS.

Here is how I run boot.

export BOOT_JVM_OPTIONS='
  -client
  -XX:+TieredCompilation
  -XX:TieredStopAtLevel=1
  -Xmx2g
  -XX:+UseConcMarkSweepGC
  -XX:+CMSClassUnloadingEnabled
  -Xverify:none'

This brings the startup time on my MacBook down from 3.2 seconds to 1.6 seconds.

The last flag -Xverify:none comes with the following warning from dev.clojure.org: Suppresses the bytecode verifier (which speeds classloading). Enabling this option introduces a security risk from malicious bytecode, so should be carefully considered.

Comments

Share your thoughts on this post here.