Frank Sommers: Could you start by giving us an overview of the GWT development process?
In order to allow us to do a lot of optimization, the basic strategy the compiler takes is monolithic compilation. That's our mantra. We figure out the exact and complete set of classes in your application, and where the entry point to your application is, and we use that constraint system to allow us to do a lot of really neat optimizations.
For example, suppose you have an application that is written in terms of the
List interface, because you are a good object-oriented developer and use abstract types. But let's say that you only ever instantiate the
ArrayList as a concrete implementation of
List. Everywhere we make a call to a
List method, we figure out at compile time that that's actually a call to an
ArrayList method, and in cases where it's appropriate, we actually inline that call.
Probably the biggest advantage that brings to the table is when we compile for different platforms: we bring in only classes that are specific to that platform. For example, when we're compiling for Firefox, we only bring the DOM implementation for Firefox into the compile. That cuts down the code size, which is a very important thing for us.
The main differences come in when you start dealing with the DOM on different browsers, and when dealing with the browser UI-level events, or the object model the browser exposes. We are able to keep that part of the problem contained away in specific classes that are targeted towards individual browsers. The compiler doesn't really have any first-hand knowledge of those differences. The GWT compile system brings in the appropriate classes for the browser, and that class contains the implementation details.
Frank Sommers: What are prototype-based objects?
foo on a particular object [that is assigned to], say, some variable
X to see if
X has a
X does, then you get whatever value happens to be there. If it doesn't, [the interpreter] walks up the prototype chain to
X's prototype object, and sees if it has one. It will walk up that chain [to] as many prototype parents as there are, until it gets to the end of the chain. If it hasn't found that still at the end, then you get an
We were able to take this construct and map on the Java idea of superclasses. For example, we set up the constructor function for
Object, and set up a prototype that has just
toString. For any classes that we derive from that, we start with an instance of
Object, which becomes the prototype for some more specialized subclass, and so on down the chain.
Scott Blum: The most difficult aspect is that Java's exact behavior is very highly specified. For example, when you have a class that's being initialized in its constructor, there are rules governing when the superclass constructor gets called, when you can make polymorphic method calls to your subclass, evaluation order, things like that. There are a whole series of those issues that are precisely specified.
That makes it difficult to have an accurate compiler, because there are a lot of corner cases you have to worry about. Sometimes the most natural and efficient thing you might want to do doesn't actually end up doing the right thing. Most people would never run into most of those cases, but it does make writing a compiler quite difficult. If they left things a bit looser, a little more unspecified, most people would never know or care about them, but it would make implementing a correct compiler a lot easier.
Frank Sommers: You mentioned that browser-specific functionality is brought into the compile process from external libraries. Can you explain how that works?Scott Blum: We have a general mechanism in the compile process that we call deferred binding. It gives you the ability to replace classes wholesale at compile time.
Imagine that you have an abstract DOM class, and that you want that to be replaced at compile time with a concrete version that would be exactly tailored to the platform you're on. Through deferred binding, you set up rules in your project configuration that allow you to specify under what conditions particular classes get swapped in for other classes.
For a basic application, most developers wouldn't have to worry about this because that's already built into our libraries. It's part of how our metadata gets inherited. But this is something you can take advantage of if you provide browser-specific implementations of your own class library.
When the compiler goes to compile something, it looks at a set of properties and generates one permutation of the compile for each of the possible states of a property. For example, there is a user agent property that has one of four different values—Firefox, IE, Opera, or Safari. The compiler will generate four versions of your application, one tailored for each one of those.
If the first permutation is Firefox, it comes up with the Firefox implementation of the DOM as being the correct replacement class, and the next time around, it will come up with one for IE, and so on.
In addition to just being able to replace classes with already written classes, the other powerful facility is to generate classes on the fly during compilation. You can run a generator which will spit out new classes that can be subclasses of classes you've already defined in your project. That is how our RPC mechanism works. All the code to serialize and deserialize your object gets generated at compile time.
Frank Sommers: Once you have those browser-specific versions, how do you deploy them so that each browser gets only the code aimed for it?
Based on those property values, the script generates the request for one of the possible compiler output permutations. So a Firefox user will get the
outerHTML for the page, which will include this selection script. The selection script realizes it's running on Firefox, and that will cause it to request as its next script the right compiler output. As a user, all you really have to worry about is copying the output from your compiler directory to your Web server.
The other place we use it in is our RPC—we use JSON as our RPC wire format. That allows us to very quickly serialize and deserialize things that go over the wire. That cuts down on the amount of processing that has to be done.
That's why, when people are creating big class libraries, a lot of what you're doing is convention-based. You have a convention for how you construct a class, you have a convention for this or that, and there is no programmatic enforcement of any of those conventions.
Scott Blum: None of the Java 5 language features are supported right now. We're strictly 1.4-based in terms of source compatibility. In terms of the actual language itself, we pretty much support everything. Inner classes, anonymous classes are supported, for instance. Pretty much anything you can express is straight Java code, you can do in GWT.
The Google Web Toolkit
Artima Interviews Google's Bret Taylor on GWT
Frank Sommers is a Senior Editor with Artima Developer. He also serves as chief editor of the IEEE Technical Committee on Scalable Computing's newsletter, and is an elected member of the Jini Community's Technical Advisory Committee. Prior to joining Artima, Frank wrote the Jiniology and Web services columns for JavaWorld.