[e-lang] Notes from latest Joe-E meeting
David Hopwood
david.hopwood at industrial-designers.co.uk
Mon Apr 30 15:28:13 EDT 2007
Tyler Close wrote:
> Hi David,
>
> The goal for the Error handling is to ensure that Joe-E code cannot
> cause any side-effects after an Error is thrown. [...]
I agree that this is the goal.
>>Remember, VirtualMachineErrors are *entirely* nondeterministic and can happen
>>at any time (at least as far as the Java spec is concerned, and we don't really
>>want to rely on properties of specific Java implementations). They do not
>>necessarily only occur at uses of 'new' or method calls.
>
> I agree we really don't want to, but they've not left us with much
> alternative. If we don't find a hack that works in practice, we'll
> have to ban catching of Error *and* finally clauses. As a test, I've
> rewritten all my code to not use finally blocks, so it is doable, but
> it might make Joe-E a harder sell.
It should certainly be possible to provide the functionality of "finally":
public interface Thunk {
void run() throws Exception;
}
public class JoeE {
...
public static void tryFinallyThrowsChecked(
Thunk tryThunk, Thunk finallyThunk)
throws Exception {
bool succeeded = false;
try {
tryThunk.run();
succeeded = true;
finallyThunk.run();
} catch (Exception e) {
if (!succeeded) finallyThunk.run();
throw e;
}
}
and then
try {
... X ...
} finally {
... Y ...
}
becomes
JoeE.tryFinallyThrowsChecked(new Thunk() { public void run() {
... X ...
}}, new Thunk() { public void run() {
... Y ...
}});
This won't win any beauty contests (because of the lack of closures, blocks or
macros in Java), but I think we can live with that given the infrequent use of
finally clauses.
Notice how the implementation does not actually use "finally". I threw away
several subtly wrong attempts that tried to use Java's "finally", before concluding
that it is irretrievably broken. The resulting Joe-E verifier rule is very simple:
don't allow "finally" in Joe-E programs at all.
Here is a more complete implementation that provides 'try/catch/finally' as well
as just 'try/finally', fixes the Java (and E) design flaw described at
<http://www.eros-os.org/pipermail/e-lang/2006-July/011371.html>, and provides
versions for use when the whole construct is not expected to throw a checked
exception. It compiles but has not been tested (and it needs to be properly
documented).
public interface Thunk {
void run() throws Exception;
}
public interface Catch {
void handle(Exception e) throws Exception;
}
public class FinallyClauseException extends RuntimeException {
private final Throwable inFinallyClause;
public FinallyClauseException(Throwable original, Throwable inFinallyClause) {
super(original + "\nfollowed by " + inFinallyClause +
" in a finally clause", original);
this.inFinallyClause = inFinallyClause;
}
public Throwable getExceptionInFinallyClause() {
return inFinallyClause;
}
}
public class JoeE {
public static void tryFinallyThrowsChecked(
Thunk tryThunk, Thunk finallyThunk)
throws Exception {
boolean succeeded = false;
try {
tryThunk.run();
succeeded = true;
finallyThunk.run();
} catch (Exception e) {
if (!succeeded) {
try {
finallyThunk.run();
} catch (Exception e2) {
throw new FinallyClauseException(e, e2);
}
}
throw e;
}
}
public static void tryCatchFinallyThrowsChecked(
Thunk tryThunk, Catch handler, Thunk finallyThunk)
throws Exception {
boolean succeeded = false;
try {
tryThunk.run();
succeeded = true;
finallyThunk.run();
} catch (Exception e) {
if (!succeeded) {
boolean handled = false;
try {
handler.handle(e);
handled = true;
finallyThunk.run();
return; // e was caught by handler
} catch (Exception e2) {
if (!handled) {
try {
finallyThunk.run();
} catch (Exception e3) {
throw new FinallyClauseException(e2, e3);
}
}
// e2 should replace e, whether or not the handler completed
throw e2;
}
}
throw e;
}
}
public static void tryFinally(
Thunk tryThunk, Thunk finallyThunk) {
try {
JoeE.tryFinallyThrowsChecked(tryThunk, finallyThunk);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void tryCatchFinally(
Thunk tryThunk, Catch handler, Thunk finallyThunk) {
try {
JoeE.tryCatchFinallyThrowsChecked(tryThunk, handler, finallyThunk);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
--
David Hopwood <david.hopwood at industrial-designers.co.uk>
More information about the e-lang
mailing list