Wednesday, June 11, 2008

Google I/O GWT Extreme! Presentation video now online

or, how I managed to render a million datapoints in Javascript in real time without crashing my browser. :)

For those who missed it, you can now catch my GWT Extreme! presentation on YouTube courtesy of Google.



You can also view the slides directly here:



I would highly recommend watching the following presentations first before watching mine:

Surprisingly Rockin Javascript and DOM Programming
Faster Than Possible Code: Deferred Binding
Resource Bundles and Linkers

If you're interested in just seeing the demo of Chronoscope zooming and rendering over 1 million datapoints, skip to about 27 minutes into my video.

-Ray

Preliminary GWT Export 2.0 release

For 1.5 users, I made two quick changes to the GWT Exporter to implement the first two features I mentioned last time: Zero-overhead Deferred Binding and 1.5 annotations.

Here's the change log:
* @gwt.export,@gwt.noexport,@gwt.exportClosure,@gwt.exportPackage now full fledged annotations instead of old 1.4 comment style
* Replacements are @Export, @NoExport, @ExportClosure, and @ExportPackage
* New deferred binding yields zero-overhead when exporting turned off
** By default, exports turned off, use <set-property name="export" value="yes"/> in your module to compile with them on

Build from the repository, or download the jar file at http://code.google.com/p/gwt-exporter

-Ray

Thursday, June 5, 2008

GWT Exporter:The Next Generation

Now that GWT 1.5 is out, it's time to look at revising my GWT Exporter library to take advantage of new features, as well as improve it speed/performance. Here are some of the features I'm looking at including in GWT Exporter 2.0

1) Support for 1.5 annotations (place @Export in front of a method to export it)
2) Export as Deferred Binding controlled by property (e.g. add ?export to URL or use <set-property) to avoid the overhead when you don't need it. For example, today Chronoscope always exports methods, even if you are including it inside of 100% GWT app. There should be zero overhead/cost when not being used.
3) Eliminate wrapper classes and bridge methods. Today, GWT Exporter generates Javascript classes which wrap GWT classes and expose methods. In 2.0, it should achieve exporting by adding non-obfuscated method aliases to GWT objects themselves.
4) Export as pure-JS libraries (no bootstrap script) with JSDoc annotations. Ideally, I copy could Javadoc from Java to JSDoc, but it's problematic since Generators don't get comments exposed to them (except for metadata)

If you have any feature suggestions for the Exporter, leave them here in the comments.

-Ray

How I lost 3 hours of my life to dynamic typing

Today, while working on integrating Chronoscope into Google's GViz API, I ran across a bizarre problem, the depths of the problem would flush 3 hours of work time down the toilet.

In order to integrate Chronoscope with GViz, I decided to provide some lightweight GWT 1.5 overlays on top of the API. To use the API, it is recommended to use the Google AJAX Loader. Quickly reading the docs, it seemed very straightforward. You start out by


<script src="http://www.google.com/jsapi?callback=handler">

After the google.load API is available, you write

function handler() {
google.load("visualization", "1", function() { alert("visualization api loaded!"); })
}

or do you?

Here comes the pain


So, if you're already familiar with the AJAX Loader API, you'll recognize I made a typo. Between the time I read the documentation, and the time I wrote the code above, the types of the parameters needed for this call morphed in my head. The third parameter can include a callback for asynchronous loading, however, the callback isn't passed as a function, but as a object, like this

google.load("visualization", "1", { callback: function() { alert("visualization api loaded!") } });

and I would have discovered this problem 3 hours earlier if it hadn't been for one fact: the wrong code locks up Firebug and generates an infinite "Loading..." in the browser tab.

If you run the wrong code inside a regular HTML page, it won't have this effect. But I was running this through an Apache Shindig IFRAME, which had loaded script containing this code via _IG_GetCachedURL, and somehow the combination of the IFRAME, the proxy loading of the script, and the cross-domain included JSAPI combined to kill Firefox. I couldn't use Firebug to set breakpoints, to inspect the network to see what stage of loading caused the failure, to see which script might be the culprit, or even to inspect the HTML DOM. I tried FF3 and installing Firebug 1.2beta, no dice. I tried Safari debugging, no dice.

Eventually, I came back to read the docs two or more times again, and discovered how I had screwed up the type of the third argument. In many other AJAX libraries, like Dojo or jQuery, they are more forgiving, and probably would have checked if the third argument was typeof(o) == "function" or "object" and acted accordingly.

I know, you're saying "Serves you right! You should RTFM more carefully!" Unfortunately, these kinds of errors are bound to be made by mere mortals, even if they do RTFM, especially with the size and complexity of todays AJAX apis.

Why do I endure using Java by using GWT my Javascript Ninja Brethren? When a simple mistake, or typo can waste half your day, you'll understand. And now that I've written a strongly typed GWT GViz/AJAX Loader wrapper, it's unlikely any GWT user will ever have to suffer the same fate.

-Ray

Wednesday, June 4, 2008

Design Patterns vs GWT Compiler: Round 1, Fight!

I've spent a lot of time maximizing performance of GWT code, and in doing so, I've tended to shy away from using too much OOP and Design Patterns, but the question is, is this fear justified? You've heard the GWT team continually tell you that you can have your abstractions without much performance loss, but is it true? It turns out, in many cases, the answer is a resounding yes.

Take for example, the Iterator pattern. I've crafted GwtQuery to iterate over native arrays, because I feared the overhead of iterators. But if you're careful in how you use the type system, the overhead turns out to be approximately, zero.

For example:


public class MyArray implements Iterable {
private String[] items = {"foo", "bar", "baz"};

public Iterator iterator() {
return new StringArrayIterator(items);
}

private class StringArrayIterator implements Iterator {

private String[] items;

private int index;

public StringArrayIterator(String[] items) {
this.items = items;
this.index = 0;
}

public boolean hasNext() {
return index < items.length;
}

public String next() {
return items[index++];
}

public void remove() {
throw new UnsupportedOperationException();
}
}
}

used as

MyArray m = new MyArray();
for(String s : m)
Window.alert(s);

The generated Javascript is

var m, s, s$iterator;
m = $MyArray(new MyArray());
for (s$iterator = $MyArray$StringArrayIterator(new MyArray$StringArrayIterator(), m.items);
s$iterator.index < s$iterator.items.length;) {
s = s$iterator.items[s$iterator.index++];
$wnd.alert(s);
}

As long as GWT can type-tighten the Iterable interface to the concrete implementing class, this output will usually hold true. The following will break the optimization and impose polymorphic dispatches:

public void onModuleLoad() {
MyArray m = new MyArray();
MyArray2 m2 = new MyArray2();
iterate(m);
iterate(m2);
}

public void iterate(Iterable m) {
for(String s : m)
Window.alert(s);
}

Here we introduce a new type, MyArray2, and we use an iterate() method which invokes the Iterable interface. Since GWT now has two classes in existence which implement Iterable<String>, it can't decide whether it has a MyArray or MyArray2, and therefore can't elide the iterator. You might ask, what happens if we remove MyArray2, but keep the iterate() method? We return to optimal code:

function $iterate(m){
var s, s$iterator;
for (s$iterator = $MyArray$StringArrayIterator(new MyArray$StringArrayIterator(), m.items);
s$iterator.index < s$iterator.items.length;) {
s = s$iterator.items[s$iterator.index++];
$wnd.alert(s);
}
}


Neat huh? If you're curious, try the same thing with Delegation, Decorator, Facade, or Flyweight, I think you'll be pleasantly surprised.

Fatality!, GWT Compiler. :)
-Ray

Tuesday, June 3, 2008

GwtQuery 0.2 released

GwtQuery 0.2 alpha is now available in the repository, both as a jar file, and as a Maven project. Nothing major has changed since the last release except to relayout the directory structure for maven.

Download it at gwtquery.com and have fun!

See the samples/ directory for some example code of how to setup a GWT module to use gwtquery.jar.

-Ray