!7
p-experiment {
allowDeferredComputation(r {
chainDeferrableComputations(f serveLater, fg(f print, f reversedString));
});
allowDeferredComputation(r {
chainDeferrableComputations(f serveNow, fg(f print, f reversedString));
});
}
sS serveNow() {
ret "Served now";
}
sS serveLater() {
ret waitThenCompute(1000, func -> S { "Served late" });
}
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;
}
callF(r);
}
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) {}
}