BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News ClojureScript Brings Clojure To The Browser via Javascript

ClojureScript Brings Clojure To The Browser via Javascript

This item in japanese

ClojureScript allows to write code using the Clojure language and compile it to Javascript. It was announced by Clojure's creator Rich Hickey (slides of Rich's ClojureScript announcement and the video of the ClojureScript announcement).

ClojureScript is a subset of Clojure, the features and libraries that are currently left out are either simply not finished yet or won't be added as they make no sense on a Javascript VM, eg. the threading support, the Java integration, etc. A list of differences between Clojure and ClojureScript is documented in the ClojureScript Wiki.

The Why of ClojureScript

The rationale for ClojureScript (from the documentation): "Javascript reaches". Javascript VMs are getting faster and are available in a growing number of places. With ClojureScript, Clojure can be used for GUI client programming, including mobile platforms which today come with powerful HTML components and Javascript VMs.  Running Clojure requires a Java VM on the client; while Java VMs might be available on desktop OSes, browsers are more ubiquitous and ship with every client-facing OS. The situation is even clearer on mobile platforms - there's is currently no significant mobile platform that ships with a Java VM capable of running Clojure out of the box. Android doesn't ship with a Java VM; it requires all bytecodes to be translated to the bytecode of its Dalvik VM; making Clojure work well on Android is an ongoing effort.

There's another use case for ClojureScript: command line utilities. Java hasn't been popular for command line utilities, particularly ones that are launched frequently, because of the JVM startup time (solutions such as Nailgun have popped up to help with that). As demonstrated by Rich Hickey, a command line utility compiled to Javascript and run with Node.js comes with a significantly lower startup time.

A popular argument for using Javascript on the server is to reuse the same code on the server and the client; particularly interesting for logic like input validation. With ClojureScript it's now possible to do the same: algorithms written in ClojureScript can be compiled to Javascript and run in the browser, but also used in the server-side Clojure codebase, where it'd be compiled to Java bytecodes. It also leaves open the option of completely dropping Java from the server by writing the application in ClojureScript and running the server side on a Javascript stack like Node.js.

The How of ClojureScript

The ClojureScript compiler contains no Javascript code, it's written in Clojure, which means the compiler needs to run on a Java VM. As a consequence ClojureScript lacks eval or other types of runtime code loading. ClojureScript is meant to be used to write programs and compile them to Javascript and not as an in-browser REPL.

However, there is a ClojureScript REPL; it's available in the ClojureScript repository. It's implemented using Clojure, which starts up Rhino, the Javascript runtime written in Java. To run a ClojureScript snippet it gets sent to the Clojure-based ClojureScript compiler which returns the Javascript code which then is run by Rhino. Doing this in a browser without access to a Clojure instance is of course not possible - at least until someone manages to compile the Clojure compiler toolchain to Javascript.

ClojureScript code can use Clojure macros. Macros are a compile time feature; if ClojureScript code references a macro call, the macro expansion is run by the ClojureScript compiler, ie. in Clojure.

While the ClojureScript  compiler currently only runs on Clojure, ClojureScript does ship with the Clojure ReaderAs a reminder: the Reader is basically Clojure's parser; it turns a textual representation of a Clojure program into Clojure data structures, which can then be evaluated.  ClojureScript comes with a Reader that can parse data in Clojure(Script) notation and hand it to the ClojureScript code as data.  ClojureScript's reader only parses, but, since there's no ClojureScript compiler available at runtime, doesn't evaluate.
ClojureScript has a Reader in order to be able to read Clojure data, a bit like Javascript can read JSON data without evaluating it. It's possible to generated Clojure data with Clojure and send it to ClojureScript and vice versa.

Actually, another part of ClojureScript's compiler tool chain, is the Google Closure toolkit. Yes - Closure with an "s" - a somewhat unfortunate name clash, but Google's Closure set of Javascript tools, in particular Closure compiler and Advanced Compilation are used.
Closure is used for a few purposes: one of them is library and dependency management, ie. to require libraries and export symbols. ClojureScript namespace definitions map to Google Closure provide and require calls. ClojureScript can thus easily use the Google Closure libraries that come with a rich set of GUI components and other features.
ClojureScript may be very close to the Clojure language, but its standard library will be a subset of Clojure's. Currently ClojureScript comes with clojure.string, clojure.set, clojure.walk, clojure.zip etc,and more libraries will be moved over. The difficulty of porting a Clojure library to ClojureScript depends on the nature of the code; purely algorithmic code that uses basic language elements to transform data will be trivial or easy to port. A library that relies on I/O libraries, threading, specific Java libraries etc will obviously require more effort to port; the extra work to factor out platform specific code will pay off.

A more interesting, but related, use of Google Closure is as an optimizing compiler backend. The code the ClojureScript compiler emits is optimized to work well with Closure's Advanced Compilation, which takes Javascript source and optimizes it, including inlining function calls, removing dead code and unused functions. One advantage of this approach is that the ClojureScript compiler doesn't have to implement these optimizations; it just delegates them to the Google Closure compiler.
Other tasks could be delegated to Google Closure in the future, such as providing source maps for debuggers, ie. data structures that can map between the generated Javascript code and the ClojureScript code that generated it. Google Closure has some support for SourceMaps, and both Mozilla and the WebKit project are working on extending their browsers, debuggers and Javascript engines with support for them.

More information about ClojureScript will become available soon; one source is Michael Fogus' blog, where he's published the first of a series of articles about the compiler. Michael works on the ClojureScript implementation. Developers interested in the inner workings of the compiler should also take a look at the ClojureScript devnotes, which hold information such as a table that lists ClojureScript language constructs and the Javascript constructs they are turned into.

The Clojure community has already started experimenting with ClojureScript. Brian McKenna has started experimenting with using macros to fight callback hell, ie. the problem with async I/O where every operation needs to supply a callback to receive the result of an operation - fine for a one-off call, but it soon gets very verbose for a sequential algorithms. There are many attempts at solutions for this in the JS world, from new languages like StratifiedJS to embedded DSL-ish libraries in Javascript.
Brian xperiments with an embedded DSL-style solution; ClojureScript, being a LISP with macros, lends itself well to this. The example handles a sequence of expressions and compiles them to nested callbacks, each will execute one expression in the sequence and then schedule the execution of the rest of the sequence using setTimeout. This is reminiscent of the programmable semicolon approach in language support for Monads (ie. Haskell's do notation) or F#'s Compuational Expressions (eg. Async Workflows). The next step would be to support more structured programming concepts like loops, ie. translate them to this continuation passing style using macros.

A blog entry by Justin Grant shows how to implement an algorithm and draw graphics using Google Closure's Canvas support.

ClojureScript is available on GitHub. For more information see the ClojureScript announcement on the clojure.com, or the ClojureScript Wiki at GitHub which contains tons of information, including the Rationale for ClojureScript, a QuickStart Guide and much more. The Clojure mailing list is also a good source for tips about working with ClojureScript as the community discusses the development workflow, tools and more.

Rate this Article

Adoption
Style

BT