Friday, December 30, 2011

10 lessons from porting JavaScript to Dart

I wrote a simple HTML5 game for my Google IO 2011 Introduction to HTML5 Game Development talk. The original game was written in JavaScript, and as an exercise I just ported the game to Dart. This post contains some lessons learned from the process.

Background: The original JavaScript code for the game is open source, as is the new Dart code.

Note: The Dart version doesn't have sound working, as the Web Audio API isn't currently working in Dart.

Straight forward port

The executive summary of the porting process is: it's pretty dang easy. Dart had two primary design constraints: it must be familiar to JavaScript developers, and it must compile to JavaScript. Having just ported over 574 lines of JavaScript to 554 lines of Dart, I can say that those two design constraints are being satisfied quite well.

To be fair, I wrote the first JavaScript version with structured classes in mind (using JavaScript's prototype system) so it was easy to port to Dart's native classes.  For example, compare the following JavaScript class:

// old JavaScript code
function Timer() {
    this.gameTime = 0;
    this.maxStep = 0.05;
    this.wallLastTimestamp = 0;
}

Timer.prototype.tick = function() {
    var wallCurrent = Date.now();
    var wallDelta = (wallCurrent - this.wallLastTimestamp) / 1000;
    this.wallLastTimestamp = wallCurrent;
    
    var gameDelta = Math.min(wallDelta, this.maxStep);
    this.gameTime += gameDelta;
    return gameDelta;
}

to the new equivalent Dart class:

// new Dart code
class Timer {

  num gameTime = 0;
  static final num MAX_STEP = 0.05;
  num wallLastTimestamp = 0;
  
  num tick() {
    num wallCurrent = new Date.now().value;
    num wallDelta = (wallCurrent - wallLastTimestamp) / 1000;
    wallLastTimestamp = wallCurrent;
    
    num gameDelta = Math.min(wallDelta, MAX_STEP);
    gameTime += gameDelta;
    return gameDelta;
  }
}

I think the Dart class syntax is easier to read, and it's a welcome relief to be able to omit all of those this qualifiers that are required in JavaScript. Regardless, I think it's safe to say that a developer versed in one language can grok the other.

So what did I learn?

1) Types rule. I know there are a bunch of JavaScript developers that have never seen a static type, and don't want to touch them. To that I say, don't be too quick to judge. Types made the porting process much quicker, because my editor and compiler caught errors much earlier for me. Did I use types for everything? Nope, but I will be using types in Dart for most things.

2) The Dart editor is very handy. With it's ability to warn me of real and potential errors as I code, I'm able to code faster. I think web developers are going to have an epiphany when they realize what they've been missing: real-time analysis of their code as they write it is a real time saver and will result in better code.

3) Frog compiler generates very logical JavaScript. Dart code will run on modern browsers via JavaScript, and Frog is the Dart to JavaScript compiler that is currently recommended due to its terse and human readable output. The Frog compiler turned my Dart code back into what was essentially the same JavaScript code that I originally wrote.  For example, check out the following JavaScript code that came from Frog:

// this JavaScript code came from Frog
function Timer() {
  this.gameTime = 0
  this.wallLastTimestamp = 0
  // Initializers done
}
Timer.prototype.tick = function() {
  var wallCurrent = new DateImplementation.now$ctor().value;
  var wallDelta = (wallCurrent - this.wallLastTimestamp) / 1000;
  this.wallLastTimestamp = wallCurrent;
  var gameDelta = Math.min(wallDelta, 0.05/*Timer.MAX_STEP*/);
  this.gameTime += gameDelta;
  return gameDelta;
}

4) Dart doesn't let me get sloppy. Thanks to types, real classes, inheritance, modifiers like static and final, and real lexical scoping, my Dart code feels more robust. I'm not allowed to slack.

5) The api.dartlang.org docs are helpful. Thanks to the new API docs, and the Dart Editor, it was easy to find my way around the core libraries.

6) Math.abs() is now num.abs(). This makes more sense to me, I'm glad they did it. For example, instead of Math.abs(-4) you will write -4.abs().

7) Grab the number of milliseconds since the epoch with new Date.now().value. Slightly more verbose than JavaScript, but this might change as the whole core libraries are going to get some major love in the beginning of 2012.

8) Dart has one falsy value: false. This is such a blessing compared to JavaScript's six falsy values. This means I had to rewrite:

// JavaScript
if (something) {
  // do stuff
}

to:

// Dart
if (something != null) {
  // do stuff
}

9) Real lexical scoping means I can drop this from instance variables. I no longer needed to write this.foo in my objects, I could just reference foo.

10) console.log() is now print(). The new print() is more terse, and works both on the server via the VM and in the browser. I'll allow it!

Summary

If your JavaScript is half way logical, you'll probably find it very straight forward to convert to Dart. There are differences, but most of the work can be handled by some regular expressions and some search and replaces. The resulting code felt more stable, as types and the tools like the Dart Editor didn't allow me to slack.

Check out the resulting Dart code for a simple HTML5 game.

Thursday, December 22, 2011

Lists and arrays in Dart

(This is Part 3 in a series about Dart. Check out Part 2, Function in Dart.)

Warning: We expect the Dart libraries to undergo potentially sweeping changes before Dart goes to alpha. This document is relevant as of 2011-12-22.

Intro

Dart is a "batteries included" effort to help app developers build modern web apps. An important "battery" is the bundled core Dart libraries, providing common and rich functionality. Dart is building a solution for large, complex web apps, and providing well tested, integrated, and common libraries is key to helping a web app developer be more productive out of the box.

The Collection libraries are a crucial set of APIs that Dart developers get for free. Much more than simple arrays and maps, the Collection library includes standard ways to filter, iterate, inspect, compose, and sort your data. This post specifically looks at List<E>, Dart's ordered, indexable collection of objects.

Aside: The Dart project is lucky to welcome Josh Bloch to the team, who will be leading the library design efforts. Expect some great things for the libraries and Dart!

Arrays are Lists

Perhaps the most common collection in nearly every programming language is the array, or ordered set of objects. Dart arrays are Lists, so look for List in the documentation. A Dart List will compile to a JavaScript array.

Fun fact: As of 2011-12-22, the word "array" does not appear in the Dart spec.

List basics

Dart supports List literals like JavaScript. A simple Dart list:

main() {
  var list = [1,2,3];
  print( list is List ); // true
}

Get the list's length, or number of elements inside of the list:

main() {
  var list = [1,2,3];
  print( list.length ); // 3
}

Access the second element in the list: (notice how Dart list indexes are 0 based, i.e. 0 is the first element, 1 is the second element, etc)

main() {
  var list = [1,2,3];
  print( list[1] ); // 2
}

If you try to reference an element that is outside the length of the list, you'll get an IndexOutOfRangeException.

main() {
  var list = [1,2,3];
  print( list[5] );  // Unhandled exception: IndexOutOfRangeException
}

Add an element to a list constructed from a list literal:

main() {
  List list = [1,2,3];
  list.add(4);
  print( list.length ); // 4
}

Now is a good time to point out that the add(object) method is optional. That is, not all implementations of List have to support it. I don't personally like optional methods, but this is where we stand as of 2011-12-22.

An example of a List that you can't add to is the fixed size List, as constructed by:

main() {
  var list = new List(3);
  list.add(4); // this throws an UnsupportedOperationException: Cannot add to a non-extendable array
               // exception thrown for Lists constructed with an initial size
}

Unfortunately, the docs right now don't clue you in that the new List(size) constructor returns a fixed size List, but follow bug 948 for the comment fix.

It's important to know that when you construct a fixed size List, that the List itself is allocated to that size and filled with nulls for the size of the List. For example:

main() {
  var list = new List(5); // [null,null,null,null,null]
  print(list[0]);  // null
}

Also important to know for JavaScript developers: Lists in Dart are not associative arrays. That is, the following code will NOT work in Dart:

main() {
  var list = new List(); // no initial size! aka EMPTY
  list[3] = 'hello'; // IndexOutOfRangeException
}

Remove an element from a list: (I know, I know, we're lacking a simple removeAt(index) function (see bug 947). See comment about Josh Bloch above and just hang tight :)

main() {
  List list = [1,2,3];
  list.removeRange(1, 1); // remove only the second element
  print( list.length ); // 2
}

To print the elements of a List, we need to add a map() function to eventually convert a List to a List<String> because Strings.join only takes a List<String>. The Dart libs are lacking a map function on collections (see bug  945).

List map(List list, converter(x)) {
  final List result = [];
  for (final x in list) {
    result.add(converter(x));
  }
  return result;
}

List<String> listToStrings(List list) {
  return map(list, (x) => x.toString());
}

main() {
  List list = [1,2,3];
  print( Strings.join( listToStrings(list), ',' )); // 1,2,3
}

Sorting

Sorting a List takes advantage of Dart's function support.

main() {
  var list = [4,1,2];
  list.sort(compare(a,b) {
    if (a == b) {
      return 0;
    } else if (a > b) {
      return 1;
    } else {
      return -1;
    }
  });
  // list is now 1,2,4
}

Iterating

Iterating over a List can be done in at least four ways. The standard, most familiar way is the for loop:

main() {
  var list = [4,1,2];
  for (var x = 0; x < list.length; x++) {
    print(x);
  }
}

There's a more terse way of using for if you don't need the current iteration index:

main() {
  var list = [4,1,2];
  for (final x in list) {
    print(x);
  }
}

The verbose way to say the above is to use a formal Iterator from the List:

main() {
  var list = [4,1,2];
  Iterator i = list.iterator();
  while (i.hasNext()) {
    print(i.next());
  }
}

And finally, if you just want to apply a function to each element of the List, use forEach:

main() {
  var list = [4,1,2];
  list.forEach(f(e) => print(e));
}

Filtering

The Collection interface, which List extends, provides a filter method, which returns a new collection with only the elements that satisfy a condition.

An example of filtering:

main() {
  var list = [4,1,2];
  var evens = list.filter(f(e) => e % 2 == 0);
  printList(evens); // 4,2
}

Of course, you don't need to inline the filtering function. Passing in a function also works:

isEven(x) => x % 2 == 0;

main() {
  var list = [4,1,2];
  var evens = list.filter(isEven);
  printList(evens);
}

Next steps

Check out the every(bool f(E element)) and some(bool f(E element)) methods to check if the List matches every condition or at least one condition, respectively.

Of course, please review the full Collection<E> docs and the List<E> docs.

Summary

Dart has Lists which are ordered sequences of objects. There is no class or interface called Array, though Lists act extremely similar to Arrays you might have encountered in other programming languages.

Dart Lists are not associative arrays like JavaScript, but Dart does have list literals for easy declaration.

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!

Next steps

Check out Part 4: Maps and hashes in Dart.

Thursday, December 15, 2011

Response to Coffeescript and Dart article on nettuts

Some slight clarifications, if I may, following a recent article on nettuts.com:
Jeremy said: ” In addition, Dart retreats from the dynamism of JavaScript, and instead exists as a somewhat static language, where types can be checked at compile time, but are erased at runtime. ”
While there are many ways to interpret “dynamism”, it’s true that Dart doesn’t have extremely dynamic features like “eval” or the ability to arbitrarily change object structure.
However, it’s important to point out that Dart is an optionally typed language, allowing a developer to write as much or as little static type information in the code as they wish. This was a pragmatic decision (as there are plenty of web developers that have been writing great untyped code, and who probably don’t want to see a type), however we also think optional typing allows a program to grow over time (as complexity increases, types can help with documentation and tools.)
Types aren’t erased at runtime, values still have their types. A string is a string, a number is a num. In fact, collections have reified types, so you can ask if a List of Strings is really a List of Strings. I think the misconception is that a few presentations out there (mine included) have said, “types don’t affect the runtime semantics of your code.” Admittedly this is something best left for language designers to debate, as real life developers want to know if types help them or just get in the way.
Dart programs can run in something called “checked mode”, which I find quite useful. It can use the types to catch errors earlier in the program, something always helpful.
James said: “Dart doesn’t seem to bring anything to the table other than a more Java-esque syntax, which many developers aren’t too fond of, myself included.”
This is a fair assessment from the early samples and demos we released. However, Dart code can be written to look nothing like Java. Remember, Dart is just a technology preview, and we are still figuring out how to write idiomatic Dart code. The community will probably evolve into something that doesn’t quite look like Java, and something that doesn’t quite look like JavaScript. It will be Dart code, and that’s good. :)
Remember that Dart code doesn’t even have to use classes, and doesn’t have to look anything like Java. For example:
hello(msg, to, wrapper) {
  return '${wrapper(msg)} to ${to}';
}
importantify(msg) => '!!! ${msg} !!!';
main() => print(hello('world', 'Seth', importantify));
Granted that’s a contrived example, but we’re doing some non-Java things in there like string interpolation, untyped code, and passing functions as first class objects. Not to mention the syntax sugar for a one line function.
Nathan said: “the end-game for Dart is to get developers writing an entirely different language altogether (preferably interpreted in a browser’s VM, instead of being precompiled to JS).” and Ryan said “Dart aims to replace JavaScript”
The end game of Dart, and CoffeeScript, and modern JavaScript, is to help developers write more complex, full featured, high fidelity, larger modern web apps. These languages are a means to an end: a better modern web. Dart isn’t out to replace anything, any more than CoffeeScript is out to replace JavaScript. Dart is out there to help show developers on other platforms that the web is a compelling and amazing place to build apps.
Finally, Alex said: “Google took rather a walled garden approach to Dart, and I get the impression they didn’t really look outside the confines of their company for inspiration.”
It’s true, Dart was launched into Technology Preview with some ideas written down. Having some code written is better than just abstract ideas, in my opinion, because shipping code wins. But Dart is not done, and it’s open source, and there’s a lot more to do. It’s incredibly open, in fact, with all the code in the open, along with the bug tracker and mailing list. I do not believe Dart is a walled garden. The real test is how the team will accept and integrate outside patches, but I don’t sense this will be an issue.
As for inspiration, there has been plenty of outside and historical influence. Lars Bak, the lead of the project, has been working on virtual machines for many years. His team was responsible for V8, so they must have learned a lot there. Gilad Bracha, leading the spec, worked on the Java language spec and generics, and definitely learned a lot of good and bad lessons there. Many on the team are former Smalltalkers, like Peter Ahe. Bob Nystrom even built his own language. Josh Bloch, of Effective Java fame, knows a thing or two about designing libraries. I’m sure I’m missing people, and I apologize. And we’d be remiss if we didn’t mention CoffeeScript as part of the inspiration, for it is clear evidence that developers are hungry for options and alternatives.


(update: this is a repost of my original comment on the article. if you'd like to respond, we should probably carry on the conversation over at the original article)

Wednesday, December 14, 2011

Learning Functions for Dart

(This is Part 2 in a series on Dart. See Part 1: Variables and optional types in Dart)

While it's true that Dart is an object oriented, class based, single inheritance language with interfaces, there's nothing forcing you to use classes. If you haven't seen a class in your life, or you don't want to use classes, you will be pleased to see that Dart can function quite nicely with, well, just functions.

Basics

The most simple function I could come up with:

hello() => 'world';

The => e syntax is shorthand for a function body of the form {return e;}.

The above is the same as:

hello() {
  return 'world';
}

Notice how the return type is omitted. Dart is an optionally typed language, so the programmer is free to omit static type declarations.

The above is the same as:

Dynamic hello() {
  return 'world';
}

The Dynamic type is the "unknown" type. From the spec: "If no static type annotation has been provided the type system assumes the declaration has the type Dynamic." You probably won't see real life code actually statically specify the Dynamic type, because the system will insert it if it needs to.

The above can also be written as:

String hello() {
  return 'world';
}

The above example statically declares String as the return type. Compare this version to the very first one-line example.

Parameters

Adding parameters to functions is familiar:

hello(msg) => msg;

Like all Dart code, types are optional for function parameters. For example, the above is the same as the below:

hello(String msg) => msg;

We think types are useful for interfaces, methods, functions, and any place you need to either communicate with your editing tools or larger team. If you haven't seen a type in your life, Dart isn't going to force types on you. However, they are useful for documentation and catching some errors early.

Multiple parameters are supported as well:

hello(msg, to) => msg + ' for ' + to;

We can do better than the overloaded + sign to concatenate strings together. The above is the same as the below:

hello(msg, to) => '${msg} for ${to}';

Ahhh, much better! Not only does the above string interpolation read better (for me, at least) there's a subtle potential performance improvement. Due to Dart's optional typed nature, using the + concatenation means the running program must first determine if it's adding two numbers or two strings. However, using the string interpolation method (eg, above) means the running program can make assumptions.

Of course the above is the same as the below, with types specified:

hello(String msg, String to) => '${msg} for ${to}';

Optional Parameters

Dart has little gems to help you write programs quickly and easily. One of those gems is optional parameters. For example:

hello(msg, to, [from]) => '${from} sent ${msg} to ${to}';

The brackets around the parameter names indicate that parameter is optional.  For example:

hello(msg, to, [from]) => '${from} sent ${msg} to ${to}';

main() => print(hello('world', 'Seth')); // doh! forgot my optional parameter
"null sent world to Seth"

Of course, the null in the above example appears because I never passed in a value for from.

The following example does pass in a value for the last (optional) parameter:

hello(msg, to, [from]) => '${from} sent ${msg} to ${to}';

main() => print(hello('world', 'Seth', 'Bob'));
"Bob sent world to Seth"

Named Parameters

Turns out this gem has a gem of its own. Optional parameters are also named parameters. Check this out:

hello(msg, to, [from]) => '${from} sent ${msg} to ${to}';

main() => print(hello('world', 'Seth', from:'Bob'));

This implies that named parameters can also be reordered when calling the function. For the below example, I added two optional and named parameters:

hello(msg, to, [from, rate]) => '${from} sent ${msg} to ${to} via ${rate}';

main() => print(hello('world', 'Seth', from:'Bob', rate:'First Class'));

Because named parameters can be reordered, the above can be rewritten as:

hello(msg, to, [from, rate]) => '${from} sent ${msg} to ${to} via ${rate}';

main() => print(hello('world', 'Seth', rate:'First Class', from:'Bob'));

This is certainly flexible stuff.

Default Parameters

Yet another bonus of using optional parameters is that they can be given default values. For example:

hello(msg, to, [from, rate='First Class']) => '${from} sent ${msg} to ${to} via ${rate}';

main() => print(hello('world', 'Seth', from:'Bob')); // doh! forgot rate
"Bob sent world to Seth via First Class"

From the spec: "If no default is explicitly specified for an optional parameter, but a default could legally be provided, an implicit default of null is provided."

It should also be noted that default values must be compile time constants. (we'll talk more about what this means in a future blog post) That is, you can't do something like hello(msg, to, [from=new foo(), rate='First Class']).


Inner Functions


Dart understands that there are plenty of developers that don't want to see a class yet still want some composability. One tool that the seasoned web developer will find useful is the "inner function" (what is the proper name here?)  Yes, you can nest functions!


An example of a nested (aka inner) function:


hello(msg, to) {
  importantify(msg) => '!!! ${msg} !!!';

  return '${importantify(msg)} to ${to}';
}

main() => print(hello('world', 'Seth'));
"!!! world !!! to Seth"


I've seen developers use these nested functions as a way to document and organize their function bodies. With proper use of nested functions, you probably don't even need comments inside a function.

Functions are First Class

Dart treats functions as first class objects, further reinforcing the notion that you don't need classes if you don't want them. For example, you can pass a function to a function:


hello(msg, to, wrapper) {
  return '${wrapper(msg)} to ${to}';
}

importantify(msg) => '!!! ${msg} !!!';

main() => print(hello('world', 'Seth', importantify));
"!!! world !!! to Seth"


Summary


Even though Dart is a object oriented, class based, single inheritance language with interfaces, developers can be quite productive and happy using only functions. In fact, if a developer never wants to see a class, they will still find Dart useful and interesting.

Dart supports simple functions with optional and named parameters, with optional default values. Dart functions are first class objects, and can be nested inside other functions.


Epilogue


Dart is not done, and has been launched as a Technology Preview in an effort to solicit early feedback from the community. Please check out this new open source structured web programming language, libraries, VM, and editor and let us know what you think. Learn more at dartlang.org and join the conversation.

The easiest way to try Dart is the browser based Dartboard, allowing you to write and run Dart code without downloading anything.

Sunday, December 4, 2011

Dart's Sweet Spot is Web Apps

I've been talking to different people interested in Dart, and a pattern is emerging. It's becoming more clear that Dart is appealing to application developers who are interested in building modern web apps. My theory is that Dart's adoption will accelerate most quickly from developers looking to build apps.

Bringing more apps to the web is a very good thing and is crucial for the long term success of the web. Right now, it's easy to argue that when software developers hear the word "apps" they think of mobile native apps. This is dangerous for the web, because if developer mindshare shifts away from the web as a place to deliver high fidelity and engaging application experiences, the web runs the risk of slowing its evolution and remaining stuck as a document platform.

Of course, the web has done tremendously well as a document platform. It's clearly the most successful and widely distributed information platform we've seen. To be fair, the web isn't a slouch for apps, either. Thanks to features like fast JavaScript engines, XMLHttpRequest, local storage, web workers, Canvas, and a slew of modern HTML5 APIs, the web can deliver relatively high performance applications to modern browsers.

Unfortunately, the typical application developer has a set of requirements and expectations that aren't easily answered by the web platform that we know and love today. For example, the application developer needs IDEs with powerful features like refactoring, integrated debugging, and comprehensive project visibility. The app developer also needs standard and integrated libraries, helping save time and increase commonality across projects. The app developer also needs a structured programming language, with the right mix of familiar features and unique optimizations for the platform.

The Dart effort is a comprehensive approach at addressing all of the above concerns: structured language, common libraries, optimized virtual machine, modularity, and editors. Dart is also a chance to take a fresh look at the web platform and build an integrated ecosystem without some of the baggage that has built up over the past 15 years or so.

While I believe that some of the web's current designers and developers will take to Dart (and certainly ActionScript developers will find much to like), I don't think web pages and web sites are the current sweet spot for Dart. It's becoming more and more clear that Dart's sweet spot is modern web apps.

The Dart team is working hard to make it easy and exciting for the app developer to build modern web apps. It's no wonder that app developers on other platforms are taking an interest in Dart, for they can see the parallels between their current environments and Dart.

Epilogue

Dart is open source and is currently in Technology Preview, so now is the perfect time to check it out and suggest features and direction. The team and mailing list are friendly, so don't be shy. You can try Dart without installing anything, with (what else?) a browser based app.

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.