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

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!