I think it's possible emulate blocking methods in GWT with a compiler
change. Suppose we have an annotation named @gwt.blocking to declare
blocking methods. The compiler requires that methods invoking methods
annotated as blocking, must be annotated too. A method annotated as
blocking, can override only a super method annotated as blocking. When
the compiler finds a call to a blocking method, this divides the
method body in two parts, a caller part and a return part. Suppose we
have these interfaces:
interface BlockingInvocation{
}
interface BlockingCallback{
void onSuccess(Object result);
void onFailure(Throwable caught);
}
For example, if we want to implement a sleep method:
interface Sleeper extends BlockingInvocation{
/**
* @gwt.blocking
*/
long sleep(long time);
}
class SleeperCaller{
public void sleep(long time, BlockingCallback callback){
Timer t = new Timer() {
public void run() {
callback.onSuccess(time);
}
};
t.schedule(time);
}
}
class SleeperTest{
/**
* This method must be annotated for compiler complaint.
* @gwt.blocking
*/
public void test(){
Sleeper s = (Sleeper)GWT.create(Sleep.class);
// this is the breaking point
Long millis = s.sleep(10000);
Window.alert("sleeping " + millis + " millis");
}
}
Then, the compiler translates SleeperTest class as:
class SleeperTest{
public void test(){
SleeperCaller s = new SleeperCaller();
s.sleep(10000, new BlockingCallback(){
public void onSuccess(Object result){
Long millis = (Long)result;
Window.alert("sleeping " + millis + " millis");
}
});
}
}
I know this is a trivial example, and control structures and scopes
are mode difficult to translate, but it's a good price to pay for
reducing client code in asynchronous cases like RPC.
Thank You, and sorry my english ;)
This approach would increase the amount of "magic" that the compiler
is adding to the written code.
In the current style of asynchronous callbacks, the actual flow of
control through the program matches the style in which the source code
is written. There really is a callback attached to the
RPC/HTTP/whatever request. This helps to ensure that the developer is
aware that the code is not executing as an atomic unit (generally so
due to the single-threaded nature of JS).
By stirring in this style of continuation passing (via the use of a
magic method), the actual control flow isn't as obvious from
examination of the structure of the source code.
--
Bob Vawter
Google Web Toolkit Team