29 July 2015
I've been enamoured with languages in the Lisp family ever since I first encountered The Structure and Interpretation of Computer Programs now more than a decade ago. At the time I was disappointed that such beautiful systems found so little use in day to day programming. Lisp seemed both deeply pragmatic (Objects!) and deeply sophisticated (Meta-circular Interpreters!). But Java, bless its heart, was the language of the day, and despite Steele's characterization, it seemed miles away from Scheme or anything like it.
For many years it seemed unlikely that Lisp would be more widely used by the working programmer. So it's with a constant sense of wonder that I look around at a rapidly expanding ClojureScript community that shares the same love for simpler yet more expressive systems. It seems fair to attribute this quickening pace of adoption to ClojureScript's steadfast dedication to pragmatism.
But always taking the practical route can cut off unforeseen avenues and vistas.
Today ClojureScript embraces the less practical and "dream bigger" side of Lisp.
ClojureScript can compile itself.
There's a lot to talk about, but first a few words on another big change.
ClojureScript now has a version number. Enthusiastic users have often asked How long till 1.0?. However 1.0 would not correctly reflect the time, effort, and feature set that comes with four years of very active development. Instead we're adopting 1.7 as this communicates the incredibly important relationship that ClojureScript has with its parent language, Clojure.
This close relationship means the differences between Clojure and ClojureScript are largely uninteresting. So much so that with the help of reader conditionals and some dedicated collaborative effort, self compilation came rather quickly.
Enough ado, let's get to it.
The following is a simple ClojureScript program that creates a definition and immediately invokes it. Click the EVAL button.
The humble result hides the enormity of the event :) If you know ClojureScript (or even if you don't), feel free to modify the source and evaluate whatever you like.
So what is happening here?
All of this happened inside of your web browser.
For the unbelievers, open Chrome DevTools, open the Sources tab and you should see something like the following:
Let's dig into details that enabled the humble result above.
So how long does it take to read the entire standard library (about 10,000 lines of code) into persistent data structures? Click the following button. This will download the entire standard library and then measure the time it takes to read all of it. Make sure to click a few times and you will observe it get faster.
On my 3.5ghz iMac this takes ~60ms under WebKit Nightly, ~80ms under Chrome Canary, and ~60ms under Firefox Nightly. These numbers are only 1.5X to 2X slower than ClojureScript JVM performance.
Now let's consider the next step, analysis.
Let's show a less trivial example. The following includes a library
import. Users of bootstrapped ClojureScript have total control how
library names are resolved to actual sources. In this case we've
configured libraries to be fetched via a simple XMLHttpRequest. In
order to expand the macros we must first get the macros file, compile
it, eval it, and then continue to parse, analyze, and compile the
This example demonstrates not only how pluggable the bootstrapped compiler is, but how anything compilable by ClojureScript JVM is compilable by ClojureScript JS.
There's little doubt that this feature enhancement will create an avalanche of new innovation. You can already run ClojureScript on your iPhone with Mike Fikes' Replete, build iOS apps with React Native, and write fast starting shell scripts with Planck or with Node.js. Suffice to say we've only scratched the surface of an iceberg of potential.
To be clear, this is not something you want to use for the traditional ClojureScript use case - building typical web applications. The output file starting size is simply too large (~300K gzipped). But there are now many new reachable targets where this cost is not a constraint as in the examples previously enumerated.
You have an amazing tool for thought at your fingertips. You can play with the latest goodies today. As I said at EuroClojure:
Keep calm and try to take over the world.