In order to start addressing our issue with error reporting, I thought
I'd start poking around at the source of all Java based exception
classes (of which both PROGRAM-ERROR and SIMLE-ERROR are part). This
source is the Condition java class.
In the class 3 methods have been defined, all related to printing of
(java based) errors:
* getMessage() [overridden 13 times, 8 call sites]
* getConditionReport() [not overridden, 1 call site]
* writeToString()
While the role of "writeToString()" is clear (it's called by PRINT to
print all Java-based objects) and hence should function differently
under different circumstances, the role separation between
getMessage() and getConditionReport() isn't quite so well defined.
This conclusion comes both from the extreme lack of documentation as
well as the following:
getConditionReport() calls getMessage() to find an "alternative
message" to be reported.
getMessage() finds out if there's a formatControl string; if there is,
it calls writeToString() to generate a message, returning that to
getConditionReport().
If getConditionReport() doesn't get an alternative from getMessage()
to return back to the caller, it calls Lisp.format() to generate a
formatted string to be presented to the user. However, this second
path will never get called, except when there's no format string....
Lisp.format() explicitly checks for a null format control string and
returns an empty string - which explains why we haven't seen crashes
from the above code paths.
So, how does that tie into the grand scheme of error reporting?
We have two places where errors are being reported:
1. the lisp debugger, which prints errors using the real (lisp based)
FORMAT function if it's autoloaded (but falls back to Lisp.format() if
FORMAT isn't autoloaded yet) which is invoked by
INVOKE-DEBUGGER-REPORT-CONDITION
2. the ERROR place holder Primitives.ERROR() which calls
Condition.getConditionReport()
The Lisp based FORMAT uses PRINT-OBJECT to print conditions.
PRINT-OBJECT.lisp defines specialized instances for several classes in
the condition class hieranchy. I know I added some in order to try to
address the exact issue we're talking about here.
The Java based Lisp.format() function uses <condition>.writeToString()
to produce its output.
With all these facts on the table, I think we need to do a few things
to clean up the mess:
- Any condition overriding getMessage() in order to call FORMAT
should be removed
- getMessage() should be documented *not* to use writeToString() on
its own instance
- getConditionReport() should be documented not to be overridden, but
to override getMessage() instead (maybe declare 'final'?)
- Remove all the special methods for classes derived from CONDITION
in the print-object.lisp file: they should all fall back to the
general method for printing conditions.
- Both INVOKE-DEBUGGER-REPORT-CONDITION and Lisp.ERROR should bind
the following variables to these listed values, in order to make sure
conditions are printed for humans:
*print-readably* nil
--> all other *print-** variables bound like the values specified for
WITH-STANDARD-IO-SYNTAX (except maybe *PRINT-ESCAPE*)
The above looks like it should solve our issues.
I'd greatly welcome any comments: it's a rather big change, judging by
the description above. Ville, you were going to look at it, maybe you
can verify if I'm half way right?
Bye,
Erik.