JavaScript (JS) and ClojureScript (CLJS)

P. Madhanasekaran

Introduction:

When a platform becomes successful, many alternative languages crop up for it -whether it is JVM, .Net, Erlang VM or JavaScript Run-time. There is a lot of debate about the merits of using JavaScript language as against the other languages that were created for JavaScript run- time. These languages transpile into JavaScript, and do not compile into byte-code as in other platforms.  CoffeeScript, TypeScript, Dart and Elm are some of these. In these languages or in the standard that was created to make good the flaws in JavaScript and standardize it, the JavaScript is transpiled into the JavaScript known to the Browser- JavaScript compiling into JavaScript!. Most of the JS frameworks like Angular, React etc. now support ES2015, the latest version of the standard. Transpiled Languages, that are better- designed, are being used more and more. CoffeeScript is mostly syntax sugar. TypeScript is the super-set of JavaScript which brings types and compile-time error checking to JavaScript. ClojureScript brings the power of Clojure to the JavaScript platform.

JavaScript run-time

JavaScript run time is everywhere. The dramatic improvements in the JavaScript execution environments led to more sophisticated Browser applications. High-performance JavaScript engines such as WebKit’s SquirrelFish, Mozilla’s TraceMonkey, and Google’s V8 proved that JavaScript could be fast. So, in addition to browser environments, JavaScript began to succeed as a general-purpose application platform. It was a historical accident that no one could have predicted, least of all the early developers of JavaScript. Although JavaScript has some flaws, it has strengths that allowed it to succeed. Recently a lot of features like web-sockets, geo-location and web-workers have been added. There are no two opinions that as a development platform JavaScript- run -time has extensive reach, portability, multi-vendor support,  optimization arms race, sophisticated tools and is implemented on all new devices. But developers feel the need for a better language. While efforts are underway to improve JavaScript, you can't significantly improve something with extensive reach in a timely manner - your improved version won't have the same reach for a long time, if ever. Thus JavaScript as it currently exists is a given, and becomes the target, rather than the source language.

The Need for a Better Language

As mentioned  above, despite JavaScript’s overwhelming success, it still has many flaws  as listed  out in the book JavaScript: The Good Parts (O’Reilly) by Douglas Crockford. We can sum them up as under:

  • No integers
  • No module system
  • Verbose syntax
  • Confusing, inconsistent equality operators
  • Confusing, inconsistent automatic operator conversions
  • Lack of block scope
  • Non-uniform iterators
  • Global variables by default
  • “This” operator which behaves differently in different places depending on the calling function.
  • No macros.
  • etc.

JS was a product of unpredictable evolution, not a carefully thought-out design process. And the vast reach and diversity of JavaScript runtimes is both a blessing and a curse: it will be difficult to create a new and improved version of the language that can replace all of the “legacy” versions deployed around the world. The attempt to create a standard has resulted in ECMAScript and the current version is ES6 and the support for it varies wildly from engine to engine. So JavaScript is here to stay, probably in its current form, for some time. Some have gone so far as to say that “JavaScript is the assembly language of the web” (the article “JavaScript is Assembly Language for the Web” by Scott Hanselman’). So now we are beginning to see the rise of tools and languages that treat JavaScript as a compilation target, much like byte-code on a virtual machine or object code in a traditional compiler. For example, the Google Web Toolkit compiles a subset of the Java language to JavaScript. We even have entirely new languages, mentioned above, designed to target JavaScript compilation directly.

ClojureScript:

ClojureScript is a version of the Clojure programming language, which compiles to JavaScript. Its primary target is web browser applications, but it is also applicable to any environment where JavaScript is the only programmable technology available. Clojure is a powerful, expressive, Lisp-like language developed for the Java Virtual Machine. ClojureScript is more than Clojure syntax layered on top of JavaScript. It supports the full semantics of the Clojure language, including immutable data structures, lazy sequences, first-class functions, and macros. Clojure was designed to have a symbiotic relationship with the JVM. It does not try to hide all the details of its host platform. In the same vein, ClojureScript does not try to hide all the details of JavaScript or the browser execution environment. ClojureScript uses the same native types as JavaScript, such as strings and numbers, and can call JavaScript functions directly without any special “wrapper” or “foreign-function” code. ClojureScript is also designed to work closely with best-of-breed JavaScript optimization tools such as the Google Closure Compiler. In summary, ClojureScript provides developers with a language that is more powerful than JavaScript, which can reach all the same places JavaScript can, with fewer of Java?Script’s shortcomings. David Nolen in “Introduction to ClojureScript” available on YouTube explains how Richy Hickey created Bitmapped Vector Trie adapting Phil Bagwell’s Array Mapped Trie for immutable data structures and other functional languages like Scala and Haskell have borrowed the same. He also discussed how virtual DOM React.js resembles that. He showed how OM, a ClojureScript a wrapper for React, updates DOM faster than a direct manipulation of DOM in JQuery or Backbone or even an update in React.js. We will see more about this later.

Development environment

ClojureScript can use the Clojure build tools like Leiningen, Boot and templates like figwheel and they are handy to learn the language. But as pointed out by Derek Slager in his talk “ClojureScript for Skeptics” there is no simple tool for those who want to try ClojureScript, especially those JavaScript developers who want to see how the great ideas in the new language work. Necessarily we have to fall back on Leiningen build tool. In the earlier article on Clojure we have seen the build tool Leiningen  and the  templates “compojure” and “compojure-app”. You can create a new lein app using

lein new figwheel example

When the project is generated, change to the directory example and execute

 lein figwheel

After the server starts, you should see the ClojureScript REPL prompt:
cljs.user>

There are primitive types such as numbers, string, boolean and RegExp. Similar to “var” in other languages  ClojureScript has symbols; but symbols are not exactly variables

The name of a symbol can contain almost any character, including hyphens and other punctuation. Things that are typically special operators in other languages, such as the arithmetic operators +, -, *, and /, are just symbols in ClojureScript, which evaluate to the built-in arithmetic function. ClojureScript also has keywords, written as symbols with a leading colon. Keywords always evaluate to themselves. Unlike symbols, they never stand in for anything else. In JavaScript, strings are often used for constants or identifiers in code; keywords fill the same role in ClojureScript. You can input some ClojureScript expressions and see the result.

(+ 1 2) ;; lists are not only data structures but also code; ie how you define expressions. The first argument is a function call and the rest are parameters to the function.

3
(println “Hello”)
Hello  ;; this side effect
nil   ;; expression should return a value and value returned by the expression

cljs.user => (def x 2)  ;; def is a special form which binds a symbol to a value.
#’cljs.user/x   ;; result
You can input the following the following Clojure/ClojureScript expressions and see the result.
(def mult (fn [x y] (* x y))) ;; function definition
(mult 2 3)
(defn add [x y] (+ x y)) ;; alternate way of defining a function using defn macro
(add 2 3)

There are the four basic data structures. Lists, vectors, maps, and sets evaluate to themselves. These data-structures/collection libraries are the corner stone  of any functional language. In ClojureScript, apart from them, they are literal data structures similar to JavaScript’s arrays and objects.


(1 2 3), (print "Hello")  ;; Lists
[:a :b :c 1 2 3]          ;; Vector
{:a 1, "b" 2}             ;; Map
#{3 7 :z}                 ; ;Set


;; You can construct a JavaScript array with the `array` function.
 

(def an-array (array 1 2 3))

;; Similarly, you can create simple JavaScript objects with `js-obj`.

 

(def an-object (js-obj "foo" "bar"))

;; (js/Date.) is equivalent to new Date().

 

(def a-date (js/Date.))

Concurrency management in Clojure is important. But as JavaScript is single-threaded no concurrency construct other than atom is used here. Core.async library is also important as with this programming model a programmer can write synchronous code and the library executes the code in what they call green threads or fibers. We will see more about it later. Now we will see how to use atom.
(def my-atom (atom 5)) ;; see to how to create an atom using atom function
#cljs/user ‘my-atom ;; value returned by above expression
(swap! my-atom + 3) ;; the new value of my-atom created with swap! is stored in different place.
8
@my-atom  ;; see how the value in my-atom is deferenced.
8

For a more detailed list of such expressions please go to https://github.com/swannodette/lt-cljs-tutorial.

Manual installation:

To understand things better, we will see how to manually install ClojureScript compiler and use it in a project - without using tools and templates, which we will use in future articles. Ensure whether you have Java-8 in your system. Then proceed to download the latest standalone ClojureScript.jar.Clojure-1.8.0 comes bundled with it.

hello_world
- cljs.jar
- build.clj
- index.html
-

For a custom project the required directory structure should be manually created as shown below: the root folder “hello_world” will hold sub-folder “src” which in turn will hold “hello_world” child folder. Create those folders using My Computer. For example E:\hello_world.

      

The downloaded cljs.jar should be copied to the root folder “hello_world”. It should also contain the build file “build.clj”. The “index.html” can also be placed in this root “hello_world” folder. The sub-folder /src/ hello_world will hold the ClojureScript code file “core.cljs”. The code for all the files are given below:

/src/hello_world/core.cljs

;; create the main project namespace
(ns hello-world.core)

;; enable cljs to print to the JS console of the browser
(enable-console-print!)

;; print to the console
(println “Hello World”)

Every CLJ/CLJS file must start with a namespace declaration matching a path on your disk:

`hello-world.core` <--> `hello-world/core.cljs`

The `(enable-console-print!)` expression redirects any printing output to the console of the browser in such a way that the `(println "Hello,world!")` prints `Hello, World!` to the console.

/build.clj

(require 'cljs.build.api) ;; ----1)
(cljs.build.api/build "src" {:output-to "out/main.js"})

  1. We require the cljs.build.api namespace. We then invoke the standard function for building some ClojureScript source - cljs.build.api/build. This function only takes two arguments: the directory to compile and a map of options. In our case a simple :output-to will suffice for now.                                        

/index.html

<html>
<body>
<script type="text/javascript" src="out/main.js"></script>   ;; ---1)
</body>
</html>

1) Note that there are no references to CLJS files. We only added a `<script>` tag to link the `index.html` page to the `main.js` file. This JS file will be generated by the  building tool while compiling the above `core.cljs` source code given earlier.

We can build the app with the following command

    java -cp "cljs.jar;src" clojure.main build.clj

When we build the application the code flow is as under:

In the “index.html” we have to refer to this file

One of the optimizations provided by Google Closure is abstracting away JavaScript environment differences The Google Closure Library (GCL) supplies an important facility missing from JavaScript: namespaces and a way to declare dependencies between them. In fact ClojureScript namespaces get compiled to Google Closure namespaces. Loading dependencies correctly across various browser targets is a surprisingly tricky affair. GCL accomplishes this by maintaining a dependency graph. When you require a namespace it will write the needed script tags in dependency order for you. You can have a look at the generated out/main.js file to the various dependencies added by GCL. Our index.html has to refer to not only main.js but also to the generated “goog” object and namespace dependencies GCL built. So index.html can be modified referring to the above “goog” as under.

/index.html

<html>
<body>
<script type="text/javascript" src="out/goog/base.js"></script>
<script type="text/javascript" src="out/main.js"></script>
<script type="text/javascript">
goog.require("hello.core");
</script>
</body>
</html>

Open  index.html with Chrome and click F12.The browser may appear as under:

Figure 1
The previous example explained some important fundamental concepts around the Google Closure Library. However it also involved a substantial amount of boilerplate. We can eliminate this boilerplate by specifying a :main entry point in the options that we pass to cljs.build.api/build. Modify build.clj as under:

/build.clj

(require 'cljs.build.api)
(cljs.build.api/build "src"
{:main 'hello-world.core
:output-to "out/main.js"})

Change your HTML to the following:

<html>
<body>
<script type="text/javascript" src="out/main.js"></script>
</body>
</html>

You can rebuild the project. Open index.html in Chrome and click F12 and see the same result.

Conclusion

JavaScript is present every- where; not only in Browser applications but also in other application. But the language was hacked within a short time -to be exact 10 days-  and its evolution was un-controlled –differing implementations in different engines. Now there is an attempt to standardize it. The current version of the same is called ES2015.This language introduces many features and it is compiled into the JavaScript the Browser knows -. JavaScript compiling into JavaScript. Even in this there are some Browser differences. Languages like CoffeeScript, Dart or ClojureScript also transpile into JavaScript. In fact ClojureScript with its immutable data-structures, lazy sequences, macros and a concurrency library like core-async is a better and a more powerful choice especially for bigger applications, if one is not put away by the Lisp syntax. “We have started using ClojureScript mainly because of excellent concurrency features introduced by core.async, which are very hard to achieve in standard JavaScript. This library alone is worth switching to Clojure. Browser application state management has become almost a no-brainer”. This is the opinion of Stanislav Yurin from “immute.co”. Araia HagHighi  from Prismatc says “ the recognition that minimizing state and side-effects yields code that is smaller, more likely to be correct, easier to test, and makes life all around better for developers. Until ClojureScript, that perspective has been really missing from frontend engineering”. Another reason adduced for adoption of ClojureScript is availability good wrappers like OM, Reagent for React.js - the UI library from Facebook that is making waves. With Clojure's persistent immutable data structures Om or Reagent is actually faster than React. The video “Immutability, Interactivity and JavaScript” by David Nolen, the Creator of OM, is good and simple introduction to immutable data structures .It shows how React.js  made use of research in Clojure and Scala world and how by allowing users to input data into mutable arrays rather than immutable data structures some of the advantage of using React.js is lost. In React documentation it is mentioned that “Dealing with immutable data in JavaScript is more difficult than in languages designed for it, like Clojure”. It also suggests users to have a look at Immutable.js library from Facebook.

The downside appears to be lack of simpler tools for those JavaScript developers who want to try ClojureScript.  Manual installation or lein templates are too much for “First Runners” to try.

Summing up:

ClojureScript brings the Power of Clojure to the web. ClojureScript is a compiler for Clojure that targets JavaScript. It emits JavaScript code which is optimized using the Google Closure optimizing compiler.

It

  • Allows us to use functional programming.
  • Uses Immutable data structures.
  • Uses Google Closure Compiler : advanced code compiling with dead code elimination
  • core.async:  makes asynchronous call look like synchronous without the use of callbacks
  • Om/Reagent/React : React provides a functional approach for rendering DOM. The React doc says “Dealing with immutable data in JavaScript is more difficult than in languages designed for it, like Clojure”. The advent of React and its virtual DOM and its growing use has paved the way for the increased adoption of immutable data structures and ClojureScript.








}