[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
New Error Proposal: suggestions to be incorporated
- To: Kent M. Pitman <KMP%MIT-MC@SU-DSN>
- Subject: New Error Proposal: suggestions to be incorporated
- From: David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
- Date: Sun, 15 May 1983 05:09:00 -0000
- Cc: Common-Lisp@SU-AI
- In-reply-to: The message of 11 May 83 05:59-EDT from Kent M. Pitman <KMP at MIT-MC>
Date: 11 May 1983 05:59 EDT
From: Kent M. Pitman <KMP @ MIT-MC>
* Based on heavy experience with the old and new error system, I feel
strongly that one consistent irritation of the old system was that
it didn't clearly distinguish between the cause and correction of
an error and that CERROR as currently proposed will perpetuate that
problem. eg, when you ran with error messages turned on but errors
ignored, typeout like "continuing will do such-and-so" was at least
irritating and frequently wrong. I put out for discussion the idea
that the CERROR should be modified as follows...
CERROR format-string-1 format-string-2 &rest args
Signal an error, with the message constructed by applying FORMAT to
format-string-1 and the arguments. If the debugger is entered, it
may choose to offer a message composed by calling FORMAT on
format-string-2 and the arguments, describing what will happen if
the error is proceeded. Continuing from such an error will cause
CERROR to return NIL. Use CERROR rather than ERROR to signal
errors for which you have written recovery code. The name stands
for "continuable error," which is too verbose to use for such a
common function.
Examples:
(UNLESS (= (LIST-LENGTH FORM) 3)
(CERROR "Wrong number of arguments in ~S"
"~1G:~[Ignore extra args~;Assume 0 for missing args~]."
FORM (< (LIST-LENGTH FORM) 3))
(SETQ FORM (APPEND FORM '(0 0))))
(DO () ((KNOWN-WORDP X) X)
(CERROR "~S is unknown, probably misspelled."
"Replace ~S and try again." X)
(FORMAT T "~&New word: ")
(SETQ X (READ)))
You have an excellent point here. Consider this added to my error proposal.
Let's amend the first example to avoid scaring people with hairy formatology:
(UNLESS (= (LIST-LENGTH FORM) 3)
(CERROR "Wrong number of arguments in ~S"
(IF (< (LIST-LENGTH FORM) 3)
"Assume 0 for missing args."
"Ignore extra args.")
FORM)
(SETQ FORM (APPEND FORM '(0 0))))
Let's also include some kind of style suggestion on the second format string
so that if a program automatically continues from the error it might be able
to incorporate the string into an explanation of what it did. This may be
overambitious since it won't work with any CERROR that asks for new input
when continued, but it could still be worthwhile for a lot of things, and
also may dovetail nicely into the condition system when we put one in some
time in the future.
* It occurs to me that the naming of CTYPECASE and ETYPECASE might
be solved in a completely different way. Rather than adding new
special forms, one could make several kinds of otherwise clauses.
The argument against this might be that it means more special cases of
symbols in the case-list position, making that position more visually
ambiguous. The counter-argument (held by some (eg, me)) is that people
should use parens around everything but the otherwise options anyway.
The Common Lisp manual is written to encourage this style.
Examples:
(SETQ X 1/3)
(TYPECASE X
((INTEGER) (- X))
((SYMBOL) (INVERSE X))
(:OTHERWISE-ERROR))
Error: The value of X, 1/3, was neither an integer nor a symbol.
(TYPECASE X
((INTEGER) (- X))
((SYMBOL) (INVERSE X))
(:OTHERWISE-CERROR))
Since OTHERWISE is not a keyword, it would be too confusing for these to
be keywords. They should be written without a colon. These are simply
magic words that are part of the syntax of these special forms.
I thought having to insert only a single letter to get this error checking
might encourage people to do it more, since it would seem painless. However
there is something to be said from a documentation point of view for your
proposal and I'll go along with it if there is general sentiment in favor of it.
I'm still mildly in favor of my original proposal for this, however.
One thing I should point out is that the "ECASE" proposal can be generalized
to COND if we decide we want that, but the "OTHERWISE-ERROR" proposal cannot be,
except in a grotesque way.
* I liked your stating explicitly not to put "Error: " at the head of
error messages. I would further like it specified that multi line error
messages should not be padded (with spaces, ";", etc.) because tools such
as the debugger (or whatever) will take care of padding lines with the
appropriate text.
(ERROR (FORMAT NIL "FOO~%BAR"))
should print out as:
>>Error: FOO
BAR
not as
>>Error: FOO
BAR
Ditto for the continuation string. The LispM currently has the bug
that proceed options come out as:
s-A: This is a proceed option
extending over multiple lines.
s-B: This is another.
when
s-A: This is a proceed option
extending over multiple lines.
s-B: This is another.
would be better. Note that (ERROR (FORMAT NIL "FOO~% BAR"))
would want to come out like
>>Error: FOO
BAR
The reason for guaranteeing something like this is that users will frequently
see the error coming out only in the debugger and may feel an urge to write
(ERROR (FORMAT "FOO~%~16TBAR")) or some such so it'll look pretty. If another
program gets ahold of such a format string and tries to use it elsewhere,
though, it'll look like garbage. Better the user should just be told flat out
that "any necessary padding for continuation lines will be taken care of". eg,
I have seen Maclisp code where users did:
(ERROR (FORMAT NIL "FOO~%;BAR"))
since they knew that the first line would have a leading ";" and the rest
would not. If the error message style is with leading, that should be supplied
on line 1 and on continuation lines by the system.
This also takes care of people who try to assume that line 1 will be shorter
than subsequent lines because they know a 20 character leader will occur on
that line and tends to produced multi-line messages where lines have balanced
lengths, rather than multi-line messages where the first line is considerably
shoerter than subsequent lines.
I'd like to see all these stylistic suggestions go into the Common Lisp manual.
* I don't see any reason why
(ABORT-PROGRAM)
can't be a synonym for what the LispM calls (SIGNAL 'SYS:ABORT). This
is a pretty useful thing to put on interrupt characters. All you have to
do is add an additional special form
(CATCH-PROGRAM-ABORTS ...) or some such which does
(CONDITION-CASE ()
(PROGN ...)
(SYS:ABORT ...))
on the LispM. In a Lisp where conditions didn't exist, people could do
the equivalent with CATCH/THROW.
In fact, I don't know why just ABORT and CATCH-ABORT aren't adequate names.
I find the word "program" ambiguous on a mainframe between meaning the
toplevel form I invoked in my read-eval-print loop and the exec command I
used to invoke the Lisp. (ie, the c-Abort vs c-m-Abort distinction on the
LispM).
In any case, I think these are valid kinds of issues for programmers to
want to do in a machine independent fashion and should be included.
The c-Abort vs c-m-Abort distinction is a real issue.
CATCH-ABORT should properly include some sort of documentation of what it is
that you are aborting from or to, as ERROR-RESTART in the Lisp machine does.
I think it's going to be too hard to specify the semantics of aborting precisely
enough to make it implementation-independent until we put condition-handling
capabilities into Common Lisp. So let's just leave it out for now, so we don't
define ourselves into a corner, even though we know very well that it is needed.
* In things like CHECK-ARG, etc. I see no reason their forms shoudln't be
evaluable multiple times. It's essential that it be clearly documented,
but that's easy to do. In the rare case that multiple evaluation would be
a screw, a simple LET will probably fix the user's problem. If we later
find out it's easy to guarantee single evaluation, it's easier to relax
things and tell him so than it is to go the other route if people have
written code depending on single evaluation.
Okay, I believe this.