Tuesday, January 24, 2012

Chromium and Dart with Dev Tools

There is a public branch of Chromium that embeds the Dart virtual machine, allowing you to run native Dart code directly in the browser. Unfortunately, only the Dartium source is available right now, but if you search hard enough, you might find an enterprisingly fellow providing pre-built binaries (warning: these may blow up your machine.)

The engineers have begun to add Developer Tools support with Dart, which starts to tell the debugging story. With a very recent build of Dartium (2012-01-24) you can try this for yourself. I found breakpoints are working, with a few caveats (eg not working with function callbacks yet.)

To see Chromium + Dart + Dev tools + breakpoints in action:



Dart is getting ready, please do try it out by learning more, browsing the API, using the Editor, or downloading the SDK. I also have a series of posts on Dart. Please let us know what you think!

Sunday, January 22, 2012

Dart SDK Quick Tour

(This is part 9 in an ongoing series about Dart. Check out part 8, This is this in Dart.)

The Dart team quietly started to provide binary Dart SDKs for download. Without compiling or syncing large source repositories, you can now compile your Dart code to JavaScript with Frog, run the Dart VM, and browse the Dart libraries.

Download

There are two options for downloading the Dart SDK: continuous nightlies or integration releases.

Choose the continuous builds if you want to live on the edge, or choose the integration builds if you want more tested releases.

For the SDK, look for either dart-linux.zip, dart-macos.zip, or dart-win32.zip. The other files (starting with DartBuild) are the Dart Editor.

After you download and unzip the archive, you'll have a dart-sdk directory. The bin directory has dart, which is the Dart VM, and frogc, the Frog compiler.

The Frog compiler

When Dart was initially announced, we shipped a DartC compiler which turned your Dart code into JavaScript code. DartC is written in Java, and is the compiler behind the Dart Editor. DartC supported incremental compilation (making the editor faster) but generated large JavaScript.

Some time later, the team released an experiment: a Dart to JavaScript compiler written in Dart itself. This compiler would generate essentially human readable, and terse, JavaScript. This Frog compiler (named after the Dart Frog) will generate only the JavaScript required to run the program, resulting in smaller output.

Running Frog

Assuming you have the following test.dart file:

main() => print("hello from dart!");

you can then compile it to JavaScript with the following command:

$DART_SDK/bin/frogc test.dart

which will generate the following JavaScript code:

//  ********** Library dart:core **************
//  ********** Natives dart:core **************
// ********** Code for Object **************
Object.defineProperty(Object.prototype, "toString$0", { value: function() {
  return this.toString();
}, enumerable: false, writable: true, configurable: true });
// ********** Code for top level **************
function print(obj) {
  return _print(obj);
}
function _print(obj) {
  if (typeof console == 'object') {
    if (obj) obj = obj.toString();
    console.log(obj);
  } else {
    write(obj);
    write('\n');
  }
}
//  ********** Library dart:coreimpl **************
// ********** Code for NumImplementation **************
NumImplementation = Number;
// ********** Code for StringImplementation **************
StringImplementation = String;
// ********** Code for _Worker **************
// ********** Code for top level **************
//  ********** Library test **************
// ********** Code for top level **************
function main() {
  return print("hello from dart!");
}
main();


The Dart virtual machine

One of Dart's primary language design constraints is that it must compile to effective and performant JavaScript. However, Dart is also designed to run in its own virtual machine, and a Dart VM is shipped inside the Dart SDK. You can use the Dart VM to run Dart code on the server or directly in a browser (with Chrome + Dart integration coming soon.)

Using the same test.dart file from above, we can run it directly on the command line with:

$ ~/Downloads/dart-sdk/bin/dart test.dart
hello from dart!

Startup for the Dart VM is very fast, too.

The libraries

The source code for the Dart libraries is also included in the SDK. You can browse the API docs at api.dartlang.org, but it's still fun to check out the actual source.

You'll find directories for the core libs, the DOM and HTML libs, and the frog compiler. You'll also see a directory named builtin, which includes runtime libraries like directories, file, sockets, and streams.

Summary

You can play with Dart today, without having to compile any code. The Dart SDK is now available for download, bundling the Frog compiler, the Dart virtual machine, and the source code for the libraries.

Next steps

Continue to part 10, Numbers in Dart.

Read more of my Dart posts, try Dart in your browser, browse the API docs, or file an issue request. Dart is getting ready, please send us your feedback!

Saturday, January 21, 2012

JavaScript WAT moments and Dart


There's a very funny 5 minute video by Gary Bernhardt from CodeMash 2012 which highlights a few WAT??!?! moments with some of our favoriate languages like Ruby and JavaScript. If you haven't seen this yet, take a few minutes and give yourself a chuckle.

Back? Cool. Let's map some of those JavaScript WAT moments to Dart and see how we do.

Example 1: Adding two empty arrays

Behold, the JavaScript:

[] + []

> "" // ?!?!?!

Not expected.

Behold, the Dart:

(note, List does not have a + operator, so here's the best we can do)

var result = [];
result.addAll([]);

print(result is List); // true.

Expected.

Example 2: Adding an empty array and empty map

Behold, the JavaScript:

[] + {};

> "[object Object]"  // ?!?!?!

That's right, a string. Not expected.

Behold, the Dart:

(note, Map does not extend collection, so not only can't we use the + operator, it doesn't make sense to directly add a Map to a List.)

var result = [];

[].addAll({}); // NoSuchMethodException: Map is not a Collection! Expected!

Not being allowed to add a map and array is expected. I am thankful the program stops if I try to do this.

Example 3: Adding an empty map and empty array

Behold, the JavaScript:

{} + []

> 0

The number zero. Not expected.

Behold, the Dart:

// nothing even close

There's no way to simply add a Map and a List. This makes sense, it is expected you can't just add a list to a map.

Example 4: Adding an object to an object

Behold, the JavaScript:

{} + {}

> NaN

Which, as the video says, is probably right. :)  However, still unexpected that this is allowed to run.

Behold, the Dart:

// nothing comes close

Neither Map nor Object have implemented the + operator, so it's impossible to try to add two objects or two maps together. It is expected that you can't simply add two arbitrary objects.

(Note: Dart does support the ability to define an operator method on a class. You are free to add plus or minus, for example, to your classes.)

Example 5: Subtracting a number from a string

Behold, the JavaScript:

"wat" - 1
> NaN

One could argue that yes, indeed, the result of subtracting a number from a string is not a number. I will grant you this. However, the fact that this line is even allowed to run and return a result is not expected.

Behold, the Dart:

var result = "wat" - 1;

// analysis will generate warning: string has no operator method '-'

// attempting to execute this will throw NoSuchMethodException

Dart will warn you that string does not have an operator method '-', but it will let you execute the program (due to types not affecting the runtime semantics of the code, because Dart embrases optional types.)

If you don't heed the warning, the above code will fail with a NoSuchMethodException, because string doesn't have a minus operator. This is expected.

Summary

The point of this post isn't to pick on JavaScript specifically, as every language eventually ends up with odd puzzlers. The point of this post is to instead remind you that there are people working very hard to reduce and remove these subtle and confusing situations from your next web programming language.

We can indeed demand more expected results from our languages and tools, and we should demand more early errors from obvious mistakes.  We need to demand less WAT?!?! moments in web development.

(BTW if anyone knows of the ES6 aka JavaScript.next aka Harmony versions of the above code, I'll be happy to include them. I'm curious if the latest work on the future of JavaScript addresses the above issues.)

This is this in Dart

(This is part 8 in an ongoing series about Dart. Check out part 7, Strings in Dart.)

One of the things that's always confused me about JavaScript is the changing definition of this. This post will show how Dart avoids the confusion with more logical bindings.

The Problem

Here's some JavaScript code:

function Awesome() {
}

Awesome.prototype.cool = function() {
    alert("inside awesome");
}

Awesome.prototype.init = function(button) {
    button.addEventListener("click", function() {
        this.cool(); // this won't work!
    });
}

var button = document.getElementById("b");
var a = new Awesome();
a.init(button);

As you can see, I've created a simple Awesome object with two methods. The cool() method prints a simple message. The init() method adds an event listener to a button, which calls cool() when clicked.

At first glance, this seems like it will work. However, because the definition of this is relative to the current context of executing code, it does not refer to the instance of Awesome. When inside the event callback, this refers to the button!

A common pattern to address this problem in JavaScript is to declare a new variable in the function which points to this before the context is changed.

For example, the following code fixes the problem:

Awesome.prototype.init = function(button) {
    var _this = this;
    button.addEventListener("click", function() {
        _this.cool(); // this works now
    });
}

This is not intuitive to developers coming from other platforms, and requires more ceremony than is probably necessary.

Dart's Solution

The following Dart code is more clear and hopefully more logical. You can see the same structure, but the main difference is that there's no changing definition of this.

#import('dart:html');

class Awesome {

  cool() {
    window.alert("inside cool");
  }

  init(button) {
    button.on.click.add((e) => cool());
  }

}

void main() {
  new Awesome().init(document.query("#button"));
}

First, the use of this is optional. Typing less code is good.

Second, because Dart doesn't change the context, or the definition of this, the cool() method resolves to the lexical scope.

Next Steps

Read more of my Dart posts, try Dart in your browser, browse the API docs, or file an issue request. Dart is getting ready, please send us your feedback!

Read part 9, the Dart SDK Quick Tour.

Wednesday, January 18, 2012

Strings in Dart

(This is part 7 in an ongoing series about Dart. Check out part 6, For loops in Dart.)

Dart brings some new ideas to Strings. If you think you know Strings, keep reading for a few surprises.

From the API docs: "A string is represented by a list of 32-bit Unicode scalar character codes."

Immutable

String are immutable objects, which means you can create them but you can't change them. You can of course build a new string out of other strings, but once created, the string's contents are fixed.

This is an optimization, as two strings with the same characters in the same order can be the same object.

var s11 = "strings are immutable";
var s21 = "strings are immutable";

print(s11 == s21); // true, contain the same characters
print(s11 === s21); // true, are the same object in memory

If you look closely at the String API docs, you'll notice that none of the methods on String actually change the state of a String. For example, the method replaceAll() returns a new String and doesn't exchange the original String.

var greetingTemplate = 'Hello NAME, nice to meet you!';
var greeting = greetingTemplate.replaceFirst(new RegExp("NAME"), 'Bob');

print(greetingTemplate != greeting); // true

Note: As of 2011-01-18, the above code doesn't work in Dart VM. See bug 429 for the status. The above code should work in Dartboard, see http://try.dartlang.org/s/yhoo for an example.

Creating

Both single and double quotes can be used to declare a String.

print('single quotes work easily');

print("double quotes work just as well");

Multi-line strings are now supported! Just use a triple quote (''' or """), with either single quote or double quote. Note the initial newline is ignored, but the last newline is not ignored!

print( '''
the initial newline is ignored
but the last newline is not ignored
''');

// is the same as

print("""the initial newline is ignored
but the last newline is not ignored\n""");

Escaping

Some languages interpret single quotes as a "literal" string, but not Dart.

print('single quotes \n don\'t make a string literal');
> single quotes 
 don't make a string literal

You can make a "raw" string by prefixing it with @. For example:

print(@'prefixing with a @ turns a string into a \n literal or "raw" string');
> prefixing with a @ turns a string into a \n literal or "raw" string

Interpolation

Dart improves on other web programming languages by introducing string interpolation. Building and joining strings is much easier now:

var s = 'string interpolation';

print('dart has ${s} which is very handy');

print("you can nest ${s + ' for fun and ${"profit"}'} with Dart");

print("concatenating strings" + " " + "is also possible with the plus sign, but we don't recommend it");
> dart has string interpolation which is very handy
> you can nest string interpolation for fun and profit with Dart
> concatenating strings is also possible with the plus sign, but we don't recommend it

Building from parts

Programmatically generating a String is best accomplished with a StringBuffer. A StringBuffer doesn't generate a new String object until toString() is called.

var sb = new StringBuffer();

sb.add("Use a StringBuffer");
sb.addAll(["for ", "efficient ", "string ", "creation "]);
sb.add("if you are ").add("building lots of strings");

var fullString = sb.toString();

print(fullString); // Use a StringBufferfor efficient string creation if you are building lots of strings

sb.clear(); // all gone!

You might be thinking, "Pffft, typing StringBuffer is so many characters. The performance difference can't be that big of a deal!" to which I reply, "The numbers don't lie."

// use new hotness: StringBuffer
buildWithStringBuffer() {
  var sb = new StringBuffer();

  for (var i = 9999; i > 0; i--) {
    sb.add(i.toString());
    sb.add(" beers on the wall\n");
  }

  var finalString = sb.toString();
}

// use old school + for string concatenation
buildWithConcat() {
  var s = '';

  for (var i = 9999; i > 0; i--) {
    s += i.toString();
    s += " beers on the wall\n";
  }

  var finalString = s;
}

// wrap a function fn with the Stopwatch class to time execution
measure(fn) {
  var sw = new Stopwatch.start();
  fn();
  return sw.elapsedInMs();
}

// the following timings are from the Dart VM
// smaller is faster is better

measure(buildWithStringBuffer); // 20

measure(buildWithConcat); // 3574 !!

As you can see, using old school + concatenation for Strings is much slower than using StringBuffer.

Note: the above times were measured in the Dart VM. When compiled to JavaScript, you will see different numbers. There is a bug for JavaScript and StringBuffer performance.

Matching

Thanks to the core Dart libraries, it's fairly easy to determine if a strings starts with, ends with, or contains another string.

var fullName = 'Cuthbert Musgrave Girdlestone, III';


fullName.startsWith('Cuthbert');            // true

fullName.endsWith('III');                   // true

fullName.contains(new RegExp('Musgrave'));  // true

Notice how the contains() method takes a RegExp object for the pattern.

Summary

Strings are immutable lists of 32 bit Unicode scalar character codes. They can be multi-line with triple quotes, or "raw" and unfiltered with a @ prefix.

Strings can be interpolated, which is preferable to concatenation via the + operator. If you must programmatically build up a String, do so with StringBuffer, which is much faster.

Strings can do a lot more than we showed here. For instance, you can split a string, create a substringtrim it, and lots more.

Next Steps

Like what you see? Learn more about Dart, its HTML libraries, and join the discussion. File a new issue if you see something missing.

Also, follow @dart_lang and +Dart Bits for more info!

Read Part 8, This is this in Dart, in which we no longer have to assign this to _this for closures.

Wednesday, January 11, 2012

For loops in Dart, or, Fresh bindings for sane closures

(This is Part 6 of an ongoing series about Dart. Check out Part 5, Generics in Dart.)

Dart has two forms of the for loop. While you may familiar with this form of iteration, the JavaScript developer will find one (surprisingly refreshing) difference. Read on!

Dart supports the typical for loop form:

for (var i = 0; i < 3; i++) {
  print(i);
}

As well as the for-in form:

var collection = [0,1,2];
for (var x in collection) {
  print(x);
}

The for-in form is sugar for the longer code which involves an iterator:

// this is the long form of for-in

var n0 = collection.iterator();

while (n0.hasNext()) {
   final x = n0.next();
   print(x);
}

// where n0 is an identifier that does not occur anywhere in the program.

This means that any object which implements Iterable can be used via for-in.

Hopefully this looks familiar so far. You might even be yawning. But wake up!

There is a subtle semantic difference between how Dart runs the for loop and how JavaScript runs the for loop.

To start, let's look at the following JavaScript code:


When this runs, what do you expect to be printed to the console? If you said 01 you'd be incorrect. This will, in fact, print 22. Go ahead, give it a shot.

What is happening here? JavaScript is binding the same variable to each of the anonymous functions inside the first for loop. Every callback sees the same i. This is certainly non-obvious to the beginning JavaScript developer.

The solution is to remember that JavaScript has function level scoping (not block level scoping). Wrapping the anonymous functions inside their own anonymous, yet immediately executed, function will create a "private" copy of the variable. For example:


We can do better! We should demand better!

Dart makes this a whole lot easier and arguably more approachable. Consider the following Dart code:

main() {
  var callbacks = [];
  for (var i = 0; i < 2; i++) {
    callbacks.add(() => print(i));
  }
  callbacks.forEach((c) => c());
}
> 0, 1

The above code is syntacticly similar to our first JavaScript example, yet behaves like the second JavaScript example. Yes, that means this prints 0 and then 1! Hurray!

Note: the for-in style loop will also get a fresh binding for i, just like the standard for loop.

If you squint, the Dart language spec specifies this exact behavior, with the following quote:
[it is] intended to prevent the common error where users create a closure inside a for loop, intending to close over the current binding of the loop variable, and find (usually after a painful process of debugging and learning) that all the created closures have captured the same value - the one current in the last iteration executed.
Warning: As of the time of this writing (2012-01-10), only the Dart VM does the right thing for the for loop. Unfortunately, DartC and Frog (the two Dart -> JavaScript compilers) are broken. Track bug 333 to follow this bug.

Further good news: ECMAScript 6 should allow for simplified syntax thanks to block scoping:

let callbacks = [];
for (let i = 0; i < 10; i++) {
  let j = i;
  callbacks.push(function() { print(j) });
}
callbacks.forEach(function(c) { c() });

Summary

Dart has two familiar forms of the for loop for iteration. In both forms, a fresh copy of the variable created by the loop is generated. Closures and anonymous functions inside of for loops will see individual variables, which is generally a more expected behavior.

Special thanks to +Bob Nystrom and his informative Dart posts on Reddit, such as this gem which provided the inspiration for this post.

Next Steps

Learn more about Dart, play with Dart in your browser, browse the API docs, enter feature requests and bugs, and join the discussion. And remember, Dart is in Technology Preview right now, things are changing and we'd like to hear your feedback!

Also, read Part 7: Strings in Dart.

Thursday, January 5, 2012

Comparing Dart, jQuery, CoffeeScript, CoffeeScript+jQuery, and JavaScript

UPDATE: Thanks to Ayose Cazorla we now have CoffeeScript+jQuery examples. And thanks to js2coffee.org we have vanilla CoffeeScript.

A neat comparison between jQuery and vanilla JavaScript hit Google+ via +Eric Bidelman, so I thought it would be fun to add vanilla Dart to the mix.

This is a fun experiment, but please don't base your decision to use one option or another based on this isolated blog post. Take a holistic approach to your evaluation.

Document is ready


// jQuery

$(document).ready(function() {
  // code…
});

// vanilla JavaScript

document.addEventListener("DOMContentLoaded", function() {
  // code…
});

// vanilla Dart

window.on.contentLoaded.add((e) => code);

// CoffeeScript+jQuery

$ -> code

// vanilla CoffeeScript

document.addEventListener "DOMContentLoaded", ->
  # code

Find all divs

// jQuery

var divs = $("div");

// vanilla JavaScript

var divs = document.querySelectorAll("div");

// vanilla Dart

var divs = document.queryAll("div");

// CoffeeScript+jQuery

divs = $ "div"

// vanilla CoffeeScript

divs = document.querySelectorAll("div")

Create a new div

// jQuery

var newDiv = $("<div/>");

// vanilla JavaScript

var newDiv = document.createElement("div");

// vanilla Dart

var newDiv = new Element.tag("div");

// CoffeeScript+jQuery

divs = $ "<div>"

// vanilla CoffeeScript

newDiv = document.createElement("div")

Add a class


// jQuery

newDiv.addClass("foo");

// vanilla JavaScript

newDiv.classList.add("foo");

// vanilla Dart

newDiv.classes.add("foo");

// CoffeeScript+jQuery

newDiv.addClass "foo"

// vanilla CoffeeScript

newDiv.classList.add "foo"

Toggle a class

// jQuery

newDiv.toggleClass("foo");

// vanilla JavaScript

newDiv.classList.toggle("foo");

// vanilla Dart

// doesn't work yet, see bug http://code.google.com/p/dart/issues/detail?id=1063
// newDiv.classes.toggle("foo");

// CoffeeScript+jQuery

newDiv.toggleClass "foo"

// vanilla CoffeeScript

newDiv.classList.toggle "foo"

Add a click handler for each <a>

// jQuery

$("a").click(function() {
  // code…
})

// vanilla JavaScript

[].forEach.call(document.querySelectorAll("a"), function(el) {
  el.addEventListener("click", function() {
    // code…
  });
});

// vanilla Dart

document.queryAll("a").forEach((el) {
    el.on.click.add((e) => code);
});

// CoffeeScript+jQuery

$("a").click -> code

// vanilla CoffeeScript

[].forEach.call document.querySelectorAll("a"), (el) ->
  el.addEventListener "click", ->
    # code

Append a new <p> to <body>

// jQuery

$("body").append($("<p/>"));

// vanilla JavaScript

document.body.appendChild(document.createElement("p"));

// vanilla Dart

document.body.nodes.add(new Element.tag("p"));

// CoffeeScript+jQuery

$("body").append $("<p>")

// vanilla CoffeeScript

document.body.appendChild document.createElement("p")

Add attribute to an element

// jQuery

$("img").filter(":first").attr("alt", "My image");

// vanilla JavaScript

document.querySelector("img").setAttribute("alt", "My image");

// vanilla Dart

document.query("img").attributes['alt'] = 'My image';

// CoffeeScript+jQuery

$("img:first").attr "alt", "My image"

// vanilla CoffeeScript

document.querySelector("img").setAttribute "alt", "My image"

Get parent node

// jQuery

var parent = $("#about").parent();

// vanilla JavaScript

var parent = document.getElementById("about").parentNode;

// vanilla Dart

var parent = document.query("#about").parent;

// CoffeeScript+jQuery

parent = $("#about").parent()

// vanilla CoffeeScript

parent = document.getElementById("about").parentNode

Clone an element

// jQuery

var clonedElement = $("#about").clone();

// vanilla JavaScript

var clonedElement = document.getElementById("about").cloneNode(true);

// vanilla Dart

var clonedElement = document.query("#about").clone(true);

// CoffeeScript+jQuery

clonedElement = $("#about").clone()

// vanilla CoffeeScript

clonedElement = document.getElementById("about").cloneNode(true)

Clear child nodes

// jQuery

$("#wrap").empty();

// vanilla JavaScript

var wrap = document.getElementById("wrap");
while(wrap.firstChild) wrap.removeChild(wrap.firstChild);

// vanilla Dart

document.query("#wrap").nodes.clear();

// CoffeeScript+jQuery

$("#wrap").empty()

// vanilla CoffeeScript

wrap = document.getElementById("wrap")
wrap.removeChild wrap.firstChild  while wrap.firstChild

Check if element has child nodes

// jQuery

if($("#wrap").is(":empty")) { ... }

// vanilla JavaScript

if(!document.getElementById("wrap").hasChildNodes()) { ... }

// vanilla Dart

if (document.query("#wrap").nodes.isEmpty()) { ... }

// CoffeeScript+jQuery

if $("#wrap").is(":empty")
  code

// vanilla CoffeeScript

code  unless document.getElementById("wrap").hasChildNodes()

Get next sibling element

// jQuery

var nextElement = $("#wrap").next();

// vanilla JavaScript

var nextElement = document.getElementById("wrap").nextSibling;

// vanilla Dart

var nextElement = document.query("#wrap").nextNode;

// CoffeeScript+jQuery

nextElement = $("#wrap").next()

// vanilla CoffeeScript

nextElement = document.getElementById("wrap").nextSibling

Next Steps

Like what you see? Learn more about Dart, its HTML libraries, and join the discussion. File a new issue if you see something missing.

Also, follow @dart_lang and +Dart Bits for more info!

Tuesday, January 3, 2012

Generics in Dart, or, Why a JavaScript programmer should care about types

(This is Part 5 in an ongoing series on Dart. Check out Part 4, Maps and hashes in Dart.)

Intro

Dart is, by most accounts, designed to be a familiar programming language. One of Dart's most interesting (and daring features for a mainstream language) is optional typing. Optional static types allow you to choose when to add the static types.

Dart has optional typing because it's a web programming language, and it's designed to scale from interactive scripts (which don't necessarily need lots of declared types) to complex, large web applications (which probably do need lots of declared types, which serve as a documentation annotation for tools and humans.)

An example of untyped Dart code:

smush(a, b) => a + b;

main() {
  var msg = "hello";
  var rcpt = "world";
  print( smush(msg, rcpt) );
}
> helloworld

As you can see in the example above, the var keyword is used to denote a variable. var is synonymous with the Dynamic, or "unknown", type. The above code is is not statically typed, yet it runs just fine.

Note the smush(a, b) method, which smushes two objects together and returns the result. Looking at this method signature, and even its definition, it's not clear exactly what that intent is or what kind of objects it works with. The original programmer's intent isn't clear, which is a problem if the development team is large or if the application itself is complex.

Nothing is stopping a developer from passing in two numbers to smush, as the example below illustrates:

smush(a, b) => a + b;

main() {
  var x = 3;
  var y = 4;
  print( smush(x, y) );
}
> 7 // technically true, but is this what we wanted to allow?

In some sense, this is the beauty of dynamic scripting languages. However, Dart is designed to support large, complex apps as well, and when you add hundreds of classes, thousands of functions, and tens of developers, this kind of ambiguity can be costly.

The typical JavaScript developer would probably first try to solve this problem by just remembering what the intent of smush is, but this doesn't scale. Second, the function would be renamed to something more clear. Third, comments would probably be added, with a note like "this methods takes two strings and concatenates them." I reckon the combination of a renamed function name and descriptive comments would get you pretty far, but they still don't express your intent to the program.

But we can do better than longer function names and more comments, for we want to say less and do more! We want our code to be our comments, and have our systems work for us and understand us!

We must demand a better solution. We must demand that our tools scale to meet our complex app needs. We must demand that our language allow us to express our intent tersely and with minimal friction!

Enter types!

Luckily, Dart gives us a safety net as we scale up our program: optional static types. By adding in simple annotations to our program code, we can express certain expectations and assertions in a way that both a human and the machine can quickly and easily grok. Once our system understands these type assertions, a whole new world of early error detection is now available. Every error caught in development is one less error caught by our users.

Let's declare that the smush method is expecting Strings:

smush(String a, String b) => a + b;

main() {
  var x = 3;
  var y = 4;
  print( smush(x, y) ); // in Checked Mode, this results in a Failed type check
}

When two numbers are passed to smush, and the program is run in Checked Mode (aka "type assertions turned on"), the system will halt execution with a "Failed type check" error.

This is awesome! Our tools caught an error for us, simply because we added some short annotations. Our tools are now working for us.

By simply adding the type declarations to the smush signature, the program understands the developer's intent and expectations and can check them for us. No comment has that power, and even a descriptive and clear function name doesn't have that power.

Think of those type annotations as assertions and documentation, all rolled up in one.

We can go further and give types to our variables x and y. This has the added benefit of generating warnings with or without Checked Mode. For example:

smush(String a, String b) {
  return a + b;
}

main() {
  num x = 3;  // note the type
  num y = 4;
  print( smush(x, y) ); // two warnings are generated here, re: type mismatch!
}
> 7 // yet the program still runs! types don't affect the program semantics

Giving type annotations to x and y, and keeping the type annotations in the smush method, allows our program to detect and warn us about this type mismatch.

This is super awesome! We don't even need to run in Checked Mode for our program to let us know something is afoot. All we had to do was add an annotation that was probably shorter than any comment you would have added to clarify just what x and y were supposed to be.

Optional types give us the powerful, yet terse, expressiveness when we need them for larger, more complex web apps, and we can omit them for our simple one page scripts. Or heck, type everything and catch nearly all type warnings early!

Yo dawg, I heard you like types, so I added types to your collections, so you can put Strings in your Lists of Strings

We've shown the helpfulness and expressiveness of types for variable declarations and function signatures. Let's take it one step farther and add another type annotation which can further tell your program, and your fellow developers, what your intentions are (and catch errors early!)

As covered in previous posts, Dart has support for collections such as Lists (arrays) and Maps (hashes). Lists store ordered collections of objects that can be retrieved via an index, and Maps store key/value pairs.

A simple example of a List:

main() {
  var digits = [0,1,2,3];
}

Adding a new element to a List is also simple:

main() {
  var digits = [0,1,2,3];
  digits.add(4);
}

However, even though I'm clearly expressing a List of numbers, the following code will still execute:

main() {
  var digits = [0,1,2,3];
  digits.add("four"); // executes, but is this what we want?
}

A couple of options spring to mind. We could rename digits to digitsOfNumbers, but that's verbose. Worst of all, not matter what we rename the variable to, we still can't express our intent to the program.

We must demand better! We must be able to tell our program that collections of things only hold certain things. We must demand that our program will warn us if an object of a different type is being added to a collection. We must demand that our programs catch errors early and help us, not hinder us!

Enter generics!

Think of generics as type annotations for your collections. With generics, you can tell your program, and other developers sharing the code, that a List of numbers is, well, actually a List of numbers.

Check it out:

main() {
  var digits = <num>[0,1,2,3];
  digits.add("four"); // BOOM, Failed type check. Program stops.
}

Thanks to the <num> annotation, the program can catch when an object with a mismatched type is added. Best of all, the error is caught early, and not when some other method tries to actually do something (incorrect) with the different object.

Dart's List interface is really a List<E> which you can read as "List of E, where E is some type." That E is a placeholder, and stand-in for a type that is declared external to the List interface definition.

These generics also help when extracting objects from a List, not just adding objects. For example, consider the following code:

add(num a, num b) => a + b;

main() {
  var names = <String>['alice', 'bob'];
  print( add(names[0], names[1]) ); // in Checked Mode, this BOOMs. Failed type check!
}

Wow, Dart is smart! It knows that add takes two numbers, and that names is a List of Strings. It also knows that objects inside of names are Strings, so when we reference names[0] (which the program knows is a String) and attempt to pass it to add(num, num), it errors with a Failed type check.

This is super duper cool! Adding a simple type annotation to our collection gives our program a tremendous amount of information, and the ability to fail quickly at the source of the bug (and not later in the program when it's too late.)  Simply being able to catch these sorts of bugs when they occur is enough to make you consider adding type annotations to your collections.

A List of Strings is a List, which sounds obvious when you say it out loud

Warning: the following section is for those who want to dive in deeper to generics, reification, and covariance. If you are new to these terms, the below might blow your mind. It's OK to stop reading here. The below isn't always the best way to write code.

One more cool part about Dart's collections and generics (aka type annotations.)  Dart will reify, or remember, the generic types for its collections. Unlike in Java, Dart's generic type annotation is not thrown away.

This means you can perform a check at runtime:

main() {
  var names = <String>['alice', 'bob'];
  print( names is List<String> ); // true!
}

OK, in retrospect, this is a totally obvious example. Trust me when I say, if you're a Java developer, your head is spinning right now.

Remember how we keep repeating that Dart is an optionally typed language? Someone (I don't know who) is going to write a function that does not specify any generic types, but the program should work anyway.

// we really recommend you don't omit the generic types
// for illustration only

awesome(List stuff) {
  // something awesome, if only I knew what was inside of stuff
  // but I was too lazy to add my generic type annotation
}

main() {
  var names = <String>['alice', 'bob'];
  awesome(names); // works! Dart lets a List<String> act as a List

  // which means
  print( new List<String>() is List );  // true!
}

When you say it out loud, it sounds obvious: a List of String is a List.

Here's the best part, and a true reflection of Dart's optional typing. If List<String> is a List, is the inverse true?  Can a List be passed to a function expecting a List<String> ?

// hurray! you added generic type annotations. your intention is clear.
awesome(List<String> stuff) {
  // something more awesome, because I know it's a List of Strings
}

main() {
  var names = ['alice', 'bob']; // I got lazy and didn't specify!
  awesome(names); // works!

  // which means
  print( new List() is List<String> );
}

Yes, the above works (though we don't recommend it!) because Dart's generics are covariant. This means List<String> is List, and List is List<String>.

But why oh why would Dart design a system that is so, well, unsound?!?!!

Remember that Dart has optional typing. This means a library author can write classes and functions without specifying any types at all. Heck, there's an army of JavaScript developers that have never seen a static type and many probably never want to see one. Hopefully the first part of this article convinced you that types are terse and useful, but Dart is built for a wide range of developers.

Now imagine that there is an untyped library that is AWESOME, and you want to use it. Your code, because you are a true Dart Viking, is fully typed.  Should you be able to mix your fully typed code with an arbitrary library that is untyped?  Yes!

// from the SuperLazyLib with zero types

awesome(stuff) {
  // you are brave
}

// from the Dart Viking, who writes clean and typed code

main() {
  var names = <String>['alice', 'bob'];
  awesome(names); // works!
}

Dart allows a mix of typed and untyped code, and as such the generics must be covariant.

If you are authoring a library, please add types. Your machines and humans will both thank you.

Summary

Demand more from your web programming language! Demand terse type annotations which help your program catch errors earlier, and your fellow developers more easily understand your intent.

Dart is a mostly familiar language by design, however it does have novel features like optional types.  Types should be thought of as annotations, or documentation, for both the machine and your fellow programmer.  Types are terse, often smaller than the comments you'd use to specify what a thing is or what can be passed to a method.

Once added, types can be interpreted by the program, allowing for bugs resulting from type mismatches to be detected early. Types also act to convey your intention and assertions to your fellow developer. This is A Good Thing (tm).

Types can be added to variables and function signatures. Types can also be given to collections such as Lists and Maps. These generics tell the program what objects are expected to be placed inside of, and retrieved from, a collection. Generics also help with tersely expressing programmer intent to both the machine and the fellow developer, and helps to catch bugs early.

Generics in Dart are covariant, which means a List of Strings is a List, and a List is a List of Strings. This is due to the fact that Dart's optional typing allows for a mix of types and untyped code to be used in the same program.

We recommend using types for method signatures, we don't recommend authoring libraries without types.

Next Steps

Learn more about Dart, play with Dart in your browser, browse the API docs, enter feature requests and bugs, and join the discussion. And remember, Dart is in Technology Preview right now, things are changing and we'd like to hear your feedback!

Also, check out Part 6, For loops in Dart, or, Fresh bindings for sane closures.

Monday, January 2, 2012

Maps and hashes in Dart

(This is Part 4 of our ongoing series about Dart. Check out Part 3: Lists and arrays in Dart.)

Warning: We expect the Dart libraries to undergo potentially sweeping changes before Dart goes to alpha. This document is relevant as of 2012-01-02.

Intro

Dart is not just a language, but a full "batteries included" effort to create a productive, familiar, and fun environment for the modern web app developer. The bundled libraries are one such "battery", including many common classes and utilities such as date manipulation, regular expressions, even asynchronous constructs like Future and Promise.

Probably the most used set of libraries will be the Collections, such as List, Map, and Set. In this post, we'll take a look at Map, which is a mapping of keys to values.

In Dart, a Map is an interface designed to manipulate a collection of keys which point to values. Maps can have null values, and can have parameterized types. Note, Maps do not subclass the Collection interface.

Dart != JavaScript: Unlike JavaScript, Dart objects themselves aren't maps or hashes.

Create, read, count, copy, and remove examples

Dart supports map literals, such as:

main() {
  var stuff = {"hello": "world"};
}

In the above example, hello is the key and world is the value.

Map literals, those declared with the {} syntax, must have Strings as keys.

var map = {};

// is the same as

var map = new Map<String, dynamic>();

However, if you declare your Map without the literal syntax (eg new Map()), you can use any object that implements the hashCode method as the key. Curious what makes a good hashCode? Josh Bloch covers hashCode in his book Effective Java, and luckily that particular topic is covered in the free Chapter 3.

Of course, the values don't have to be strings:

main() {
  var stuff = {"hello": 4};
}

Dart Maps can contain null values, too:

main() {
  var stuff = {"hello": null};
}

Retrieving a value from a map is familiar:

main() {
  var stuff = {"hello": "world"};
  print( stuff['hello'] ); // world
}

If you look for a key that isn't in a Map, you will get a null in return:

main() {
  var stuff = {"hello": "world"};
  print( stuff['foo'] ); // null
}

Adding a new key/value pair to an existing map is also familiar:

main() {
  var stuff = {"hello": "world"};
  stuff['Dart'] = 'Is Cool';
  print( stuff['Dart'] ); // Is Cool
}

Use the length getter to return the number of key/value pairs in the Map:

main() {
  var stuff = {"hello": "world"};
  stuff['Dart'] = 'Is Cool';
  print( stuff.length ); // 2
}

Removing a value from a map, which also removes its key, is straight forward:

main() {
  var stuff = {"hello": "world"};
  stuff['Dart'] = 'Is Cool';
  print( stuff['Dart'] ); // Is Cool
  stuff.remove('hello');
  print( stuff.length ); // 1
  print( stuff['hello'] ); // null
}

You can copy a Map with a named constructor:

main() {
  var stuff = new Map.from({"hello": "world"});
  print( stuff['hello'] ); // world
}

Iterating

There are a few ways to iterate through the contents of a Map. If you want to access both the key and value at the same time, the forEach method will work nicely.

main() {
  var stuff = {"hello": "world", 'Dart': 'Is Cool'};
  stuff.forEach((k,v) => print(k));
}

Notice how, in the above example, that both the key and the value as passed to the callback function for every iteration of forEach.

No order is implied, do not depend on a certain order of keys and values being returned via forEach.

If you are only interested in just the keys, or just the values, use getKeys() and getValues(), respectively. Both methods return a Collection object.

main() {
  var stuff = {"hello": "world", 'Dart': 'Is Cool'};
  var keys = stuff.getKeys();
  print( keys.length ); // 2
  keys.forEach((k) => print(k)); // hello, Dart
}

putIfAbsent

A fun method on Map is putIfAbsent(K key, V ifAbsent()). It will first if the key exists, and if not, will run the ifAbsent function and will use the return value as the value for the key. For example:

main() {
  var stuff = {"hello": "world", 'Dart': 'Is Cool'};
  stuff.putIfAbsent('foo', () {
    // calculate something awesome
    return 'bar';
  });
  print( stuff['foo'] ); // bar
}

Parameterized types, aka Generics

I haven't written a post on generics yet, so please bear with me if you don't know what generics are. If you do, you'll be pleasantly surprised at how they've been simplified. If you don't know what generics are, think of them as annotations to help you and your tools understand more about the types you'll use with objects such as collections.

Maps can be specified with parameterized types, which allow you to say what kind of types you want to store inside the map. For example, perhaps you want a Map of Strings to integers. Without generics, you'd have to just hope everyone (including you) puts in String/int pairs, and you'd probably have to add a bunch of assertions to ensure that they (or you) did. However, with generics, the tools and runtime can help ensure that the code maps Strings to integers.

(The examples in the post so far have not specified any parameterized types.)

In Dart, you can be more specific about your Map, and actually say "A Map that maps Strings to integers" in this way:

main() {
  var stuff = <String, int>{'four': 4, 'five': 5};
  print( stuff['four'] ); // 4
}

The above is the same as:

main() {
  var stuff = new Map<String, int>();
  stuff['four'] = 4;
  stuff['five'] = 5;
  print( stuff['four'] ); // 4
}

Our tools come to the rescue when someone (definitely not you, because you're a Dart viking) accidentally assigns the wrong type. For example, if you run the below in Checked Mode:

main() {
  var stuff = new Map<String, int>();
  stuff['four'] = "oh uh!"; // Failed type check: type String is not assignable to type int
  print( stuff['four'] ); // won't get this far
}

Now that's what I'm talking about! For the small cost of specifying the expected types at object instantiation time, the system (in checked mode) will warn you the wrong type is being used, and the program will stop running. (again, if you're in checked mode, this is true) Check out the above example and play with the "checked mode" toggle.

You can go further and even specify the parameterized types statically, such as:

main() {
  Map<String, int> stuff = new Map<String, int>();
  stuff['four'] = "oh uh!"; // warning here if NOT in checked mode
  print( stuff['four'] ); // won't get this far
}

Now the system has even more information, so you will get further warnings even if you're not in checked mode! The program will still run if you have checked mode turned off, since the above program still works. However, by specifying the static type for stuff, you've added enough annotations to give you warnings that something isn't quite right. Try the above code yourself, with and without "checked mode" enabled.

As mentioned above, if you are using the non-literal syntax to declare a Map (such as new Map()) then you can use any object that implements hashCode as the key.

Summary

Dart's bundled libraries includes a Map interface, which can map a key (as long as it implements hashCode) to a value for easy lookup. The interface has the standard methods for creating, reading, updating, and deleting key/value pairs, as well as some new methods like putIfAbsent(). Just like in JavaScript, Dart Maps can be created with a literal, terse syntax (however, this restricts you to using only Strings as keys.) Unlike JavaScript, though, Dart objects aren't themselves Maps.

Just as Dart has optional types, parameterized types are optional as well. They are quite useful when you're writing method signatures and interfaces, as they convey even more intention and documentation about the expected containers and objects. The more type annotations you can add, the more rich documentation can be extracted and the more the tools can warn you when things don't go as planned.

Next Steps

Read Part 6 on Generics in Dart, or Why JavaScript developers should care about types.

The core Dart libraries will almost certainly undergo sweeping changes now that Josh Bloch has joined the team. For now, though, there's still a lot you can do with Dart's lists. As you work with the libraries, remember that Dart is in Technology Preview mode, and we really want to hear your feedback.

What do you need from the libraries? Let us know at the mailing list or please file an issue. Thanks!

Read more about the Map interface at the docs, and check out all the libraries at api.dartlang.org.

Disclaimer

I'm probably required to say that the views expressed in this blog are my own, and do not necessarily reflect those of my employer.