Adventures in Dart land

The Dart language was unveiled by Google less than 2 years ago as a new “language for the web”, and, like most people, I didn’t give a f… much attention as it was in its early stages and I couldn’t really put my finger on what it was trying to solve, and for whom.

After coding Dart during several weeks (on this cool project) I can pretend to be familiar enough with the language and tools to tell you a bit about it. You’ll be surprised, for Dart isn’t what you think it is.

Did I like it? Yes, I genuinely enjoyed working with Dart.

Should you learn it? Give it a look – you might like it, and learning new languages make you a better coder anyway.


Foreword

Dart is still under development

While the Dart language and core libraries are stable, the compiler and Dart Editor are still under development. It hasn’t reached v1.0 and everything was updated every week during the project.

The pace of updates has slowed down and it seems pretty solid now, but I feel there is still room for improvement.

Dart doesn’t require the Dart VM to run

Dart (dart2js) compiles to JavaScript with source maps and with optional (and very efficient) minification built-in, thank you.

Actually the VM isn’t integrated in Chrome yet, so you need Chromium to test it natively. I’m curious how they will eventually communicate about it because it’s both something they will want to brag about, and something they will be hated for…

You can use any code editor

Although the Dart Editor (a lightweight custom Eclipse build) will probably be the most up to date regarding the language features, there are many options for coding in Dart – including IntelliJ IDEA, Sublime Text, or simply the command line.

Why can Dart be amazing for you?

If you’re a JavaScript developer:

  • Dart language and tooling can make you more productive,
  • Dart really improves the DOM API in a cross-platform way (see below about APIs), hiding browser inconsistencies even for CSS properties, so you don’t feel the need for something alienating like jQuery,
  • the Web UI library offers a model-driven development like Backbone.js, Ember.js or AngularJS.

If you’re a Flash developer:

  • Dart language and tooling is closer to the ActionScript experience than Javascript,
  • you also benefit from the better DOM API (see above),
  • the StageXL library is an incredibly complete and robust Flash-like engine for Canvas.

If you’re a back-end developer:

  • use the same language and share code between the server and the client,
  • use a modern event-driven I/O API like the cool guys of node.js, vert.x,…

The Dart language is not JavaScript

A casual look at some samples may let you think it’s similar to JavaScript, or Typescript (which is an awesome way to enhance without betraying JavaScript). The language was designed to be immediately familiar, but that’s only the surface.

JavaScript isn’t easy, but the language is quite simple if you can wrap your head around the prototypes, scoping rules and quirks – then you have to start digging into a mess of thousands of libraries doing mostly the same thing in subtly different ways.

The Dart language is very different in practice and a lot richer as you start digging – but there are no more prototypes and quirks. It is very consistent thanks to a solid set of core libraries, and can eventually perform better than vanilla JavaScript because it is designed to prevent all the “bad practices” that make it difficult for browsers to JIT efficiently.

Watch: Dart VM creators talk on web performance.

What is the generated JavaScript worth?

Honestly, the generated code isn’t super readable, but it’s understandable 😉 It isn’t too bloated and performs well – especially if you compile for deployment: by default the code has a lot of explicit type checking that are inserted for debugging.

As expected nowadays, the cross-compiler generates source maps which make it easy to debug if the browser support them.

The cross-compiler has a built-in minifier which, thanks to the type annotations and inference, does a fantastic job at removing useless code (tree shaking): you can safely link to huge libraries and only get the relevant bits included in the final script. You can only dream of that in JavaScript.

Typing, type inference and strict mode

Dart is an optionally typed language with a great type inference at the tooling level.

At run time, Dart is essentially dynamic: type annotations serve only for tooling and at run time the important thing are the “values”.

There is also a stricter “checked mode”, that is enabled by default during development: it which will report more type errors at run time (typically function parameter types and ‘assert’ statements).

This is a very powerful aspect of Dart, although it seems to need some fine-tuning: it’s sometimes too strict, sometimes too loose. Well, sometimes there is a reason for the weird things.

var s = "Hello";     // s is a String
s.indexOf("needle"); // okay
s.indexOf(12);       // runtime exception: int is not a subtype of String
s["length"];         // runtime exception: String has no []= operator

s = 12;              // okay: s is now an int
s.indexOf("1");      // runtime exception: int has no 'indexOf' method
s.foo = 12;          // runtime exception: int has no 'foo' method

num v = 12.0;        // 'num' is like 'var' for numbers
int i = v;           // runtime exception: double is not an int

var a = [1, 2, 3];   // a is a List
a[10] = 2;           // runtime exception: RangeError

Mind: blown

Read again the previous code sample: you still get all these run time exceptions when cross-compiled to JavaScript*.

If you know JavaScript well, this should blow your mind, as the only runtime exception you should get in JS is when calling .indexOf on a Number.

* some exceptions will only happen with “checked mode” enabled which isn’t enabled by default in the JavaScript generator.

Types and arrays ranges are enforced at run time

This means Dart JavaScript contains various safeguards, making sure that you access existing methods, manipulate the right types and don’t overflow arrays. It’s not magical, it can lead to ugly generated code.

For dart2js to do a good job, it seems to help to:

  • carefully type class fields and function arguments,
  • use ‘final’ or ‘const’, and don’t initialize variables to ‘null’ (unless there is a good reason for).

It is worth noting that the annotations are here mostly to help you make sure that you manipulate the right types, and with enough hints, the compiler will be able to skip some checks.

You can read the Google+ thread about the article for more details about type annotations.

Numeric types are tricky to use

Although it’s important to explicitly use int and double for optimal performance, be warned that there is (for now) no implicit conversion between int and double and you will get brutal runtime exceptions (in checked mode) unless you approach numbers very carefully:

  • num slot can receive any numeric value; this is nicer to expose nums in function parameters,
  • int/double slot must receive exactly the right type,
  • always use <num or double>.toInt() and <num or int>.toDouble() to convert numbers.

Classes are no syntaxic sugar

There is no concept of “dynamic object” as in JavaScript, where you can modify any object or prototype to inject/modify fields and methods: objects and types have a static structure.

In a sense this is a good thing because browsers’ JIT love that you don’t modify objects structures and field types during their lifetime.

No [brackets] access

Unless you use operator overloading (woah!) and define the []= operator.

This is a big change compared to dynamic languages like JavaScript and ActionScript: you can’t use brackets access to read/write properties of an arbitrary object, even for existing fields.

This is probably the language feature that annoys me the most as there is no simple workaround, except by using completely different code patterns like big switch/cases. While I’m at it, I find Dart Reflection quite ugly (disclaimer: I don’t like C# Reflection either), and it’s WIP, and it doesn’t even cross-compile to JavaScript anyway.

Awesome sauce

There is a lot to like in Dart (cf. A tour of the Dart language), so here are a few things worth bragging:

Functions

You’ll love their short syntax, default values, optional or named arguments (in the tour).

Function callbacks can be strongly typed. And like with C# delegates you can declare the callback signature (it’s called a typedef).

Dart has automatic closures (‘this’ is preserved when you call a callback) – it has pros and cons which are out of the scope of this overview, but make sure you fully understand this “detail”.

Strings

First class String interpolation, as expected in the finest languages:

num i = 42;
var s = “hello ” + i; // exception
var s = “hello $i”; 
var s = “hello ${i - 2}”;

You can also do “raw” strings, and multi-line strings using three quotes (single or double).

Chain everything!

Now that’s unique: no need to ‘return this’ anymore to chain method calls, as anything can be chained thanks to the “cascade” operator.

var img = new Image()
  ..src = "logo.png"
  ..classes.add("logo")
  ..style.opacity = "0.5";

Classes

The class system is very rich – here’s a little glimpse:

class Point {
  num x;
  num y;
  
  // syntaxic sugar to set this.x/this.y
  Point(this.x, this.y);

  // named constructor 'new Point.fromJson(json)'
  Point.fromJson(Map json) {
    x = json['x'];
    y = json['y'];
  }
}

And there’s more: mixins, abstract classes, initializer lists, redirected constructors, constant constructors, factory constructors… they added everything but the kitchen sink.

Event model

If you’re an ActionScript developer you may be a fan of Signals. Well Dart Streams (actually Streams are a lot more than events) look very much like signals and you’ll use them everywhere, from DOM events to built-in Ajax.

var button = document.query("#mybutton");
button.onClick.listen( (e) { // click event
  var url = "http://example.com/userCount";
  HttpRequest.getString(url).then( (result) { // ajax load event
    print("User count: $result");
  });
});

Imports

Dart has a powerful way to handle modularity and libraries. This is a topic to read carefully to get started: Dart Libraries and Visibility.

Also worth noting that everything is public unless it starts with an underscore.

APIs

On the client (see previous snippets), Dart reinvents the DOM API, for instance:

  • you don’t use document.createElement but new DivElement(),
  • you don’t need to worry about browser specific properties (window.devicePixelRatio, div.style.transition,…),
  • you would use Dart’s Stream event system instead of the usual add/removeListener,
  • and many other additions/changes that replace libraries like jQuery.

More about Dart Standard Libraries here.

Dart and JavaScript interop

You don’t simply communicate between Dart (even compiled to JS) and JavaScript, you must use interop magic. It looks complicated at first sight, but it makes a lot of sense if you keep the contact surface between Dart and JavaScript minimal.

Why Dart

Now that’s the good question to ask, and I’m not sure what to answer. Although I fully appreciate all the subtleties and quirks of JavaScript, I had this occasion to use Dart, I liked it and I’m motivated to use it again 🙂

Maybe because Dart is a clever and original language, with a great potential for performance growth compared to JavaScript, and it really tries to improve the development experience in the browser by subtly changing its API.

It’s a shame that Google doesn’t have plans (yet?) for AOT on mobile which could solve the scripting performance problem of PhoneGap-like solutions (web app packaged as a native app).

8 thoughts on “Adventures in Dart land

  1. Cool, that you like Dart, I’ve been playing with it since it got released and I admint it’s a pretty nice language, so will we eventually see Dart syntax in Flash Develop?

  2. Pingback: Philippe.me » Type annotations for the CreateJS Toolkit

Leave a Reply

Your email address will not be published. Required fields are marked *