over-constrained problem of Web development. Thanks largely to the success of Google Maps and Gmail, several points had simultaneously become
clear to us:
End users really liked and wanted ˲
browser-based applications.
Rich client-side interactivity (for ˲
example, Maps and Gmail) made such
applications much more responsive
and usable than typical Web 1.0 page-at-a-time applications and thus much
more compelling.
Each major browser was techni- ˲
cally capable of enabling such interactive applications. They could all run
JavaScript and support dynamic HTML,
but bugs, inconsistencies, and proprietary APIs and behaviors prevented any
single JavaScript program from working consistently and efficiently on the
majority of the modern browsers.
Support for the JavaScript lan- ˲
guage itself—that is, for the “pure”
language syntax and core JS libraries,
excluding DOM APIs—was, to our surprise, quite consistent and reliable
across browsers.
In other words, the browser—in
particular, XHR, JavaScript, and the
DOM—presented a capable, albeit
frustrating, platform for delivering applications.
ples—thoroughly defeat static analysis. All this extra stuff—the metadata
and verification tools—seemed an awful lot like an ad-hoc static type system
and a compiler front end.
Furthermore, we badly wanted an
IDE. Our experience had thoroughly
convinced us that IDEs are a boon
to productivity, quality, and maintenance. Features that are status quo
in modern Java IDEs such as code
completion, debugging, integrated
unit testing, refactoring, and syntax-aware search were virtually nonexistent for JavaScript. The reason for this,
again, is related to the dynamism of
JavaScript. For example, it isn’t possible to provide sound code completion
in a JavaScript editor in the general
case because different runtime code
paths can produce different meanings
for the same symbols. Consider this
legal JavaScript:
function foo(m) {
alert("You called foo with
the message: " + m); }
if (dayOfWeek() == "Wednesday") {
foo = 3;
}
foo("Hello?"); // [ 1]
Box 1. Shape hierarchy as it might appear in Javascript (a) and Java (b).
function Shape() { }
Shape.prototype.getArea = function() { }
(a)
function Circle(radius) { this.radius = radius; }
Circle.prototype = new Shape();
Circle.prototype.getArea = function() { return this.radius this.radius
Math.PI; }
function Square(length) { this.length = length; }
Square.prototype = new Shape();
Square.prototype.getArea = function() { return this.length this.length; }
function displayArea(shape) { alert(“The area is “ + shape.getArea()); }
Javascript Reservations
At the same time, we had questions
about whether JavaScript was a good
language in which to write business-critical applications. On the one hand,
JavaScript is a flexible, dynamically
typed language that makes certain
types of code easy to write and pleasantly succinct. On the other hand, that
same flexibility can make JavaScript
harder to use within a team environment because there is no easy way to
enforce the use of consistent conventions automatically across an entire
codebase. It is true that, with significant extra work, a JavaScript team
could insist that all script be augmented with extra metadata (JSDoc, for example) and then use additional tools to
verify that all script complies with the
agreed-upon conventions. This would
also necessarily restrict the developers to a statically analyzable subset of
JavaScript, since some of JavaScript’s
most dynamic constructs—eval() and
the with statement are good exam-
function runTest() {
var shape1 = new Circle( 3);
var shape2 = new Square( 2);
displayArea(shape1);
displayArea(shape2);
}
In Java language for use with GWt
(b)
abstract class Shape {
public abstract double getArea();
}
class Circle extends Shape {
private final double radius;
public Circle(double radius) { this.radius = radius; }
@Override public double getArea() { return radius radius Math.PI; }
}
class Square extends Shape {
private final double length;
public Square(double length) { this.length = length; }
@Override public double getArea() { return length length; }
}
static void displayArea(Shape shape) { Window.alert(“The area is “ +
shape.getArea()); }
static void runTest() {
Shape shape1 = new Circle( 3);
Shape shape2 = new Square( 2);
displayArea(shape1);
displayArea(shape2);