svoid allowDeferredComputation(Runnable r) {
try {
callF(r);
} catch (RuntimeException e) {
Throwable e2 = innerException(e);
if (!e2 instanceof DeferredComputationException) throw rethrow(e);
}
}
sclass DeferredComputation {
new Flag done;
O value;
Throwable error;
Runnable continuation, onError;
void setContinuation(Runnable r) {
synchronized(done) {
if (!done.isUp()) ret with continuation = r;
}
if (error == null)
callF(r);
else
if (onError != null)
callF(onError);
else
printStackTrace(error);
}
void setValue(O value) {
synchronized(done) {
if (done.isUp()) fail("setValue/setError called twice");
this.value = value;
done.raise();
}
callF(continuation);
}
void setError(Throwable error) {
synchronized(done) {
if (done.isUp()) fail("setValue/setError called twice");
this.error = error;
done.raise();
}
if (onError != null)
callF(onError);
else
printStackTrace(error);
}
O getValue() {
assertTrue(done.isUp());
ret value;
}
}
// f1: func -> A, f2 : func(A) -> B, returns: B
static O chainDeferrableComputations(O f1, fO f2) {
O result;
try {
result = callF(f1);
} catch (RuntimeException e) {
Throwable e2 = innerException(e);
if (!e2 instanceof DeferredComputationException) throw rethrow(e);
final DeferredComputation f = e2/DeferredComputationException.future;
final new DeferredComputation future2;
f.setContinuation(r {
try {
future2.setValue(callF(f2, f.getValue()));
} catch e {
future2.setError(e);
}
});
throw DeferredComputationException(future2);
}
ret callF(f2, result);
}
static A waitThenCompute(int delay, final F0 f) {
final new DeferredComputation dc;
doLater(delay, r {
try {
dc.setValue(callF(f));
} catch e {
dc.setError(e);
}
});
throw DeferredComputationException(dc);
}
sclass DeferredComputationException extends QuickException {
DeferredComputation future;
*(DeferredComputation *future) {}
}