Make `AssertionError` extend `Exception`
See original GitHub issueCurrently, AssertionError
extends java.lang.Error
, which is wrong. It should instead extend ceylon.language.Exception
.
The Java conventions are:
- Never throw a
java.lang.Error
unless the system is totally hosed - Never catch an
Error
without re-throwing anError
or ending the process. The very rare exception to this rule is when the potential for a specificError
is expected
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions.
It’s true that (2) is sometimes violated, for instance, by recovery code in servlet containers, but those few violations are irrelevant to this issue.
These conventions are good and correct, because in the face of an Error
, the integrity of the process is in doubt. Carefully reviewed code that must run correctly, such as the following, may fail with an Error
, which is totally unexpected:
try {
// do stuff
}
finally {
// the following may fail to complete due to an Error such as
// StackOverflowError or OutOfMemoryError.
clearAuthenticationTokenInThreadLocal(); // simple code that "can't" fail
}
A caller should not attempting to recover from an Error
thrown by the above code, for example:
shared void run() {
while (true) {
try {
serveRequest();
}
catch (Throwable t) {
log(t);
// It’s totally wrong to continue here!
}
}
}
However, this recovery code is perfectly fine:
while (true) {
try {
serveRequest();
}
catch (Exception e) {
log(e); // probably bad user input or something
reportErrorToUser(e);
}
catch (Error e) {
try {
log(e);
reportErrorToUser(e);
}
finally {
throw e; // system is totally hosed, be sure to re-throw
}
}
}
This recover code would also be fine without catch (Error e) { ... }
.
In Ceylon 1.3.3, Error
s in the form of AssertionError
are thrown for perfectly ordinary things, such as failed parses, bad input, and common programming bugs such as equivalents to Java’s NullPointerException
, ClassCastException
, and IndexOutOfBoundsException
(these should never happen in finally
blocks).
For Java code calling Ceylon code, this causes a significant problem. Java code may, and often does, catch (Exception e)
, which misses Ceylon AssertionError
s which should be caught and handled.
For general/top-level Ceylon recovery code, having AssertionError
extend Error
requires the rather awkward catch (Exception | AssertionError e)
, rather than the simple catch (Exception e)
.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:1
- Comments:52 (51 by maintainers)
Top GitHub Comments
Because if an
AssertionError
(or any otherException
) happens in a very important finally block, “it’s your own damned fault.” But anError
is impossible to protect against, and therefore the presence of one indicates that the application state may be compromised, at least without the caller having very special knowledge of the code that was called (e.g. SOE in the type checker)But I’ve already said that in different ways here, and in prior conversions.
The SDK isn’t an application, so that makes sense. In the IDE, it is at least suspect that
Throwable
s are caught, rather thanException | AssertionError
s. But I haven’t looked at the specific code you are taking about.Yes, I am.
You’d want
catch (Exception | AssertionError)
, for sane course-grained, top-level recovery.Ok, really, that’s the last from me. I’ve made all of my arguments, so I’m going to unsubscribe from this thread.
You’re lucky, then!