Trying Clojurescript

clojure/clojurescript

I had heard about Clojure for a while, but didn't pay too much attention to it. It wasn't until I watched an intro video by @mpjme that I gave it serious consideration. That was in late 2015, and I have been playing with it on and off ever since.

Installation

The first thing I discovered after deciding to try it myself, was that it was rather difficult to install. Both clojure and clojurescript needed the jvm, and I didn't have that installed - because... it's java, and java sucks. There is a node.js implementation of clojurescript, but I didn't discover it until later. Unlike with python or with javascript (both of which I first installed many years ago), it took me quite a while to get my first .clj program running. Plus, despite all the hype about clojure and the repl, my version didn't even support simple things like pressing the up key. I had to run the interpreter through readline. (Though this may have been due to something I did wrong during installation.) Now, things are somewhat easier. I simply use lein (not 100% sure how to pronounce that) to install and compile whatever I need.

Despite the initial difficulties in installing clojure, learning clojure has truly been fun and easy. The minimal syntax can be learned in minutes, and having a lot of parentheses does not frighten me. After getting used to the styling convention, I now find the code produced by this language to be quite elegant.

S-Expressions and Syntax

The key to having far less syntax than other languages is in S-expressions. Clojure is based on lisp, which really popularized this construct. I'll give one example of why these are cool. Take for example this snippet of valid clojure code:

(+ 5 4 3 2 1)

This adds together the numbers from five to one (giving 15). The S-expression is defined as [open parenthesis] + function name + zero or more arguments + [close parenthesis]. Here, the function is "+" (the sum function), and the arguments are 5, 4, 3, 2, and 1. From a purely personal point of view, I find this to be quite elegant. However, it can be argued that this is objectively better, as shown in this piece of code:

(+ 1 (* 3 4) 2)

This take the sum of: one, the product of three and four, and two, giving 15. The parentheses of the function calls are almost like the parentheses in a mathematical equation (which is no accident). In another programming language (such as my "native" language, javascript), it might be written like so:

1 + 3 * 4 + 2

In most languages like this, this expression also yields 15, but only because the syntax of the language tries to match the "order of operations" we learned in elementary school. It executed ((1 + (3 * 4)) + 2) rather than (((1 + 3) * 4) + 2) because of an unwritten convention that had to be learned by programmer and programming language, rather than a simpler logic. Not only does this get far more complicated when other operators are involved, but the programmer must memorize and correctly apply all of them in order to write bug-free code. By requiring the developer to use brackets (for function calls), clojure is essentially forcing the developer to write less ambiguous - and therefore clearer - code. For more information about syntax in programming languages (in a very approachable format), I refer you to a talk by Douglas Crockford on YouTube.

Resources

Two resources were very helpful in my learning process. The first was this web app hosted on Heroku. It was a useful little playground for testing different lines of code (as I mentionned earlier, using the repl directly in the command line was a little painful at the time). Now, I'm sure there are dozens of such apps on the internet. The second, which is still useful - and probably always will be - is the cljs.info interactive cheatsheet. It is an excellent reference to the language. I keep that tab open every time I develop in clojurescript.

Web Development

Where I really came to enjoy using clojure(script) was in front-end web development. I've landed on a library called reagent, which I really like. It generates html from lists of keywords, properties, and children (which has helped me understand how JSX works). It manages application state using modified clojure "atoms" à la angular.js. Here is a sample that I wrote:

(defn App []
  [:div
   [:h1 {:id "statusbar"} (@app-state :status-text)]
   [Controls]
   [Board]])

This is one of the components (the main component) of an implementation of Conway's Game of Life that I wrote a little under a year ago. Parenthetically, this isn't a bad demo app to try when learning a new front-end language. It involves rendering something to screen, automatic (timed) state changes, and human interaction (interval sliders, etc).

The defn App [] defines a function with the name App that takes no parameters. This is used just like a component in react.js. Reagent has some built-in, such as divs and spans, and all the usual ones that are included in HTML. The [:div ... ] is one example of that. It creates a div that contains a status bar, a control panel, and a board (the latter two are custom components). The [:h1 {:id "statusbar"} ... ] is a header with an id. Of particular interest is the (@app-state :status-text) part. app-state is the name of the atom that holds the state of the whole application, the at-symbol "dereferences" it, and the :status-text extracts that particular property from it. Any time :status-text changes, the h1 will be altered on screen. Lastly, the [Controls] and [Board] are simply including custom-made components that are defined elsewhere (either in the same file or in other files).

Another library that has been really fun to use is figwheel. Figwheel enables hot code reloading. Using it, anytime you change your code and save the file, the client running in the browser will automatically update without refreshing the page. Because the application state is usually kept apart from the rest of the application (as is often the case with functional programming languages), you don't need to repeat the actions that brought you to that point in your app. This allows for near real-time feedback to your coding. It's pretty cool.

The most recent thing I've been learning about is a built-in module called core.async. This provides "go-blocks" (based off golang's "goroutines"), which are building on communicating sequential processes (CSP). I need to do some more reading and experimenting with them, but I'll write about that in a future post.

Conclusion

I like clojure and clojurescript. But what I like about them is the language itself, not so much the environment around it. There's a lot of overhead to clojure development - in terms of installation (though this has changed somewhat), the jvm (for clojure proper), compilation steps, files and folders, and even computer RAM. It's not like javascript or elm (to be covered in an upcoming post), where you can run one program (node or the elm compiler, respectively), and write one or two files in order to have a functioning web page. Clearly it's more appropriate for larger, more complex applications. Despite all this, you should check it out!

Add a comment

Previous Post Next Post