[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

New Error Proposal: suggestions to be incorporated



    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.