Saturday, 18 January 2014

Dart vs. ClojureScript: first impressions

Update: I have spent some more time with both Dart and ClojureScript since I wrote this, and I have written more about this in Dart vs. ClojureScript: two weeks later.

Dart is a relatively new programming language created by Google for client-side web development. I've started looking into it a bit as I am planning a local Dart Flight School event as one of the organisers for GDG Houston. In particular, I spent about an hour going throught the Darrrt code lab. Having done this, I was curious to see how the same application coded in ClojureScript would compare.

First impressions

Let me start by saying I haven't done much JavaScript programming since about 1996, and I am generally more comfortable with the server side of web programming than the client side. This makes a big difference in how I approach Dart and ClojureScript, as I am relatively unfamiliar with the underlying platform. Someone with a lot of experience with JavaScript and client-side web programming may approach these languages differently.

Dart

My first impression of Dart is that it is very Java-like. It's features include:

  • static typing
  • object-oriented
  • Java-like syntax
  • generics
  • exceptions

One of the major ways in which Dart is different Java is that it has lexical closures and first-class functions, which are welcome additions. Additionally, I think Dart has pretty good documentation and a fairly decent standard library.

ClojureScript

This isn't my first time using ClojureScript; nonetheless, it's still different enough in tooling and language details that it takes me a little bit more time to get up and running compared to a traditional Clojure project. However, the biggest problem that I ran into isn't the language, but the library.

With Dart, things like making asynchronous HTTP requests and manipulating the DOM are baked right into the standard library. With ClojureScript, it's not quite as straightforward. Do I use JavaScript primitives, the Google Closure library, or look for a ClojureScript library that wraps Closure or raw JavaScript? In the end, I used ClojureScript libraries such as Domina and storage-atom.

Some comparisons

Even within this short code lab, there are a few places where the differences between the two languages was remarkable.

Serialisation

The code lab includes both storing bits of information in HTML5 local storage and loading data from an external file. In the case of Dart, I found it to be somewhat painful as it required transforming things into or from JSON.

For example, a Dart PirateName class requires the following JSON read/write code:

final String TREASURE_KEY = 'pirateName';

class PirateName {
  PirateName.fromJSON(String jsonString) {
    Map storedName = JSON.decode(jsonString);
    _firstName = storedName['f'];
    _appellation = storedName['a'];
  }

  String get jsonString => '{ "f": "$_firstName", "a": "$_appellation" }';
}

PirateName getBadgeNameFromStorage() {
  String storedName = window.localStorage[TREASURE_KEY];
  if (storedName != null) {
    return new PirateName.fromJSON(storedName);
  } else {
    return null;
  }
}

In comparison, with ClojureScript we can use the reader and a map instead of an object. Combining this with the storage-atom library makes reading from and writing to local storage trivial.

(def storage (local-storage (atom {}) :pirate-storage))

; write to local storage
(swap! storage assoc :pirate-name name)

; read from local storage
(:pirate-name @storage)

Likewise, in Dart, reading a set of names and appellations from an external file requires decoding JSON:

class PirateNames {
  static _parsePirateNamesFromJSON(String jsonString) {
    Map pirateNames = JSON.decode(jsonString);
    names = pirateNames['names'];
    appellations = pirateNames['appellations'];
  }
}

In Clojure, we can just use read-string.

Built-in functions

While Dart's library has a fairly decent set of functions for doing things like interacting with the DOM, it doesn't have some of the functionaly that ClojureScript has built-in.

For example, compare (rand-nth names) to:

final Random indexGen = new Random();

name = names[indexGen.nextInt(names.length)];
Asynchronous code

With ClojureScript, you can use core.async as described by David Nolen to write asynchronous code that reads logically. Dart has no comparable functionality (though it does have functionality to support asynchronous code in general). While using core.async for this code lab is probably unnecessary, I can definitely see how it could make a more complex application easier to understand and maintain.

Final thoughts

I can definitely see how Dart is a big improvement over JavaScript. Nonetheless, I think that ClojureScript is fundamentally a more powerful language. It's shortcomings in comparison to Dart seem to generally lie in terms of libraries, which can be easily written by the community. As such, while I have found Dart interesting, and will continue to learn more about it, at this time I would lean more towards using ClojureScript in a project.

TrackBacks

Comments