Planck Road Ahead

January 22, 2017

Planck 2 is currently in beta, and is closing in on a release. The main feature in Planck 2 will be support for Linux and there will be a future blog post about that aspect.

In the meanwhile, I wanted to describe a few of the new features in Planck 2 relative to Planck 1.17.




Async Shell

Thanks to contributions by Jonathan Leonard, the planck.shell namespace gains the ability to execute long-running shell commands, calling back when complete.

cljs.user=> (require 'planck.shell)
nil
cljs.user=> (planck.shell/sh-async "sleep" "30" prn)
nil
cljs.user=> ;; 30 seconds go by
{:exit 0, :out "", :err ""} 

This can be extremely useful when writing scripts given the lack of threads in ClojureScript.

Hi-Res Timer

In Planck 1.17, cljs.core/system-time is at millisecond resolution:

cljs.user=> (system-time)
1485114862744
cljs.user=> (time (apply + (range 1e7)))
"Elapsed time: 17.000000 msecs"
49999995000000

Planck 2 monkey-patches cljs.core/system-time with native code returning nanosecond-resolution timestamps:

cljs.user=> (system-time)
182818380.748193
cljs.user=> (time (apply + (range 1e7)))
"Elapsed time: 16.948683 msecs"
49999995000000

Interrupt Forms Generating Output

If you evaluate something like (range) in a ClojureScript REPL, you are pretty much done. In Planck 1.17, because it is using Fipp, you at least get a stream of integers being printed.

In Planck 2, you can interrupt this stream by hitting Ctrl-C, and you will be returned to the REPL prompt with all of your REPL state intact:

cljs.user=> (def a 3)
#'cljs.user/a
cljs.user=> (range)
(0
 1
 2
 3
 4
 ...
 4907
 4908
 4909
^C
cljs.user=> a
3

This mechanism doesn't work for forms that don't generate any printed output, like (apply + (range)). This is because it hooks into the underlying print call to check for Ctrl-C—and thanks to Fipp, large forms result in multiple print calls.

This has been one of my favorite new features. I've found it to be useful surprisingly often: It works for large output forms (not-necessarily infinite), and I suppose I'm impatient at times, and just want to get back to the REPL prompt.

Source for REPL-defined forms

In Planck 1.17, the source REPL special only works for def forms that exist in namespaces that are loaded from source (either on disk, or JARs, or bundled with Planck).

Planck 2 extends this capability to forms interactively entered at the REPL:

cljs.user=> (defn square
       #_=>  [x]
       #_=>  (* x x))
#'cljs.user/square
cljs.user=> (square 3)
9
cljs.user=> (source square)
(defn square
 [x]
 (* x x))
nil

This works even if you redefine a def that came from source (showing your REPl-entered definition). And, in that case, if you subsequently require the namespace, passing the :reload flag so that the def reverts to the on-disk form, source will reflect that.

Planck Classpath Environment Variable

If you have libraries that you frequently use, you can put them in PLANCK_CLASSPATH and they will always be available, unless specifically overidden by -c.

I find this useful in order to always have Andare always available in order to mess with core.async or a locally-built copy of the port of test.check to self-hosted ClojureScript available for use when messing with spec.

Trying it Out

If you'd like to try Planck 2 before it is released, on macOS, just do

brew install --devel planck

On Linux it is fairly easy as well, just clone the repo, ensure you have the needed deps, and build it:

cd planck
./script/build
Tags: Planck ClojureScript Bootstrap