Errors CONDITION-RESTARTS hasn't been included
!!! What to do with this use of "construct"? -kmp 3-Sep-91Common Lisp constructs are described not only in terms of their behavior in situations during which they are intended to be used (see the “Description” part of each operator specification), but in all other situations (see the “Exceptional Situations” part of each operator specification).
A situation is the evaluation of an expression in a specific context. at a particular point in time? -kmp 5-Sep-91A condition is an object that represents a specific situation that has been detected. Conditions are generalized instances of the class condition. A hierarchy of condition classes is defined in Common Lisp. A condition has slots that contain data relevant to the situation that the condition represents.
An error is a situation in which normal program execution cannot continue correctly without some form of intervention (either interactively by the user or under program control). Not all errors are detected. When an error goes undetected, the effects can be implementation-dependent, implementation-defined, unspecified, or undefined. See Section 1.4 (Definitions). All detected errors can be represented by conditions, but not all conditions represent errors.
Signaling is the process by which a condition can alter the flow of control in a program by raising the condition which can then be handled. The functions error, cerror, signal, and warn are used to signal conditions.
The process of signaling involves the selection and invocation of a handler from a set of active handlers. A handler is a function of one argument (the condition) that is invoked to handle a condition. Each handler is associated with a condition type, and a handler will be invoked only on a condition of the handler's associated type.
Active handlers are established dynamically (see handler-bind or handler-case). Handlers are invoked in a dynamic environment equivalent to that of the signaler, except that the set of active handlers is bound in such a way as to include only those that were active at the time the handler being invoked was established. Signaling a condition has no side-effect on the condition, and there is no dynamic state contained in a condition.
If a handler is invoked, it can address the situation in one of three ways:
It can decline to handle the condition. It does this by simply returning rather than transferring control. When this happens, any values returned by the handler are ignored and the next most recently established handler is invoked. If there is no such handler and the signaling function is error or cerror, the debugger is entered in the dynamic environment of the signaler. If there is no such handler and the signaling function is either signal or warn, the signaling function simply returns nil.
It can handle the condition by performing a non-local transfer of control. This can be done either primitively by using go, return, throw or more abstractly by using a function such as abort or invoke-restart.
It can put off a decision about whether to handle or decline, by any of a number of actions, but most commonly by signaling another condition, resignaling the same condition, or forcing entry into the debugger.
define-condition.
Figure 9–1. Standardized Condition Types
All condition types are subtypes of type condition. That is,
(typep c 'condition) → trueif and only if c is a condition.
Implementations must define all specified subtype relationships. !!! Barrett: I don't understand this sentence.Except where noted, all subtype relationships indicated in this document are not mutually exclusive. A condition inherits the structure of its supertypes. !!! Barrett: It would be easier to say that conditions are classes, but maybe there is some reason to avoid doing so?
The metaclass of the class condition is not specified. Names of condition types may be used to specify supertype relationships in define-condition, but the consequences are not specified if an attempt is made to use a condition type as a superclass in a defclass form.
\Thenextfigure\ lists the \term{condition} \term{types} defined in this specification. \issue{UNDEFINED-FUNCTIONS-AND-VARIABLES:COMPROMISE} \issue{DATA-IO:ADD-SUPPORT} \issue{PARSE-ERROR-STREAM:SPLIT-TYPES} \issue{ACCESS-ERROR-NAME} \issue{READER-ERROR:NEW-TYPE} \issue{FLOATING-POINT-CONDITION-NAMES:X3J13-NOV-89} \issue{COMPILER-DIAGNOSTICS:USE-HANDLER} \displaythree{Condition Types}{ arithmetic-error&package-error&storage-condition cell-error&parse-error&stream-error condition&print-not-readable&style-warning control-error&program-error&type-error division-by-zero&reader-error&unbound-slot end-of-file&serious-condition&unbound-slot-instance error&simple-condition&unbound-variable file-error&simple-error&undefined-function floating-point-overflow&simple-type-error&warning floating-point-underflow&simple-warning } \endissue{COMPILER-DIAGNOSTICS:USE-HANDLER} \endissue{FLOATING-POINT-CONDITION-NAMES:X3J13-NOV-89} \endissue{READER-ERROR:NEW-TYPE} \endissue{ACCESS-ERROR-NAME} \endissue{PARSE-ERROR-STREAM:SPLIT-TYPES} \endissue{DATA-IO:ADD-SUPPORT} \endissue{UNDEFINED-FUNCTIONS-AND-VARIABLES:COMPROMISE}
The next figure shows operators that define condition types and creating conditions.
define-condition | make-condition |
Figure 9–2. Operators that define and create conditions.
The next figure shows operators that read the value of condition slots.
Figure 9–3. Operators that read condition slots.
error or cerror; non-serious conditions are typically signaled with signal or warn. Barrett: Definitional.
All \term{serious conditions} should be \subtypesof{serious-condition}.
make-condition can be used to construct a condition object explicitly. Functions such as error, cerror, signal, and warn operate on conditions and might create condition objects implicitly. Macros such as ccase, ctypecase, ecase, etypecase, check-type, and assert might also implicitly create (and signal) conditions.
A number of the functions in the condition system take arguments which are identified as condition designators. By convention, those arguments are notated as
datum &rest arguments
Taken together, the datum and the arguments are “designators for a condition of default type default-type.” How the denoted condition is computed depends on the type of the datum:
The denoted condition is the result of
(apply #'make-condition datum arguments)
The denoted condition is the result of
(make-condition defaulted-type
:format-control datum
:format-arguments arguments)
Barrett wanted this added so that implementations could do something more elaborate than just the given type without interfering with user programs. There's a lot of mail about simple-condition-disjointness-bug which might or might not actually turn into a formal issue someday. -kmp 2-Feb-92where the defaulted-type is a subtype of default-type.
The denoted condition is the datum itself. In this case, unless otherwise specified by the description of the operator in question, the arguments must be null; that is, the consequences are undefined if any arguments were supplied.
Note that the default-type gets used only in the case where the datum string is supplied. In the other situations, the resulting condition is not necessarily of type default-type.
Here are some illustrations of how different condition designators can denote equivalent condition objects:
(let ((c (make-condition 'arithmetic-error :operation '/ :operands '(7 0)))) (error c)) ≡ (error 'arithmetic-error :operation '/ :operands '(7 0)) (error "Bad luck.") ≡ (error 'simple-error :format-control "Bad luck." :format-arguments '())
If the :report argument to define-condition is used, a print function is defined that is called whenever the defined condition is printed while the value of *print-escape* is false. This function is called the condition reporter; the text which it outputs is called a report message.
When a condition is printed and *print-escape* is false, the condition reporter for the condition is invoked. Conditions are printed automatically by functions such as invoke-debugger, break, and warn.
When *print-escape* is true, the object should print in an abbreviated fashion according to the style of the implementation (e.g., by print-unreadable-object). It is not required that a condition can be recreated by reading its printed representation.
No function is provided for directly accessing or invoking condition reporters.
There are stylistic recommendations for the content of the messages output by condition reporters, but there are no formal requirements on those programs. If a program violates the recommendations for some message, the display of that message might be less aesthetic than if the guideline had been observed, but the program is still considered a conforming program.
The requirements on a program or implementation which invokes a condition reporter are somewhat stronger. A conforming program must be permitted to assume that if these style guidelines are followed, proper aesthetics will be maintained. Where appropriate, any specific requirements on such routines are explicitly mentioned below.
(error "This is a message") ; Not recommended (error "this is a message.") ; Not recommended (error "This is a message.") ; Recommended instead
Error: ” or “Warning: ” or even just freshline or newline. Such text is added, if appropriate to the context, by the routine invoking the condition reporter.
It is recommended that a report message not be followed by a trailing freshline or newline. Such text is added, if appropriate to the context, by the routine invoking the condition reporter.
(error "This is a message.~%") ; Not recommended (error "~&This is a message.") ; Not recommended (error "~&This is a message.~%") ; Not recommended (error "This is a message.") ; Recommended instead
If the calling routine conventionally inserts some additional prefix (such as “Error: ” or “;; Error: ”) on the first line of the message, it must also assure that an appropriate prefix will be added to each subsequent line of the output, so that the left edge of the message output by the condition reporter will still be properly aligned.
(defun test ()
(error "This is an error message.~%It has two lines."))
;; Implementation A
(test)
This is an error message.
It has two lines.
;; Implementation B
(test)
;; Error: This is an error message.
;; It has two lines.
;; Implementation C
(test)
>> Error: This is an error message.
It has two lines.
The operation of the condition system depends on the ordering of active applicable handlers from most recent to least recent.
Each handler is associated with a type specifier that must designate a subtype of type condition. A handler is said to be applicable to a condition if that condition is of the type designated by the associated type specifier.
Active handlers are established by using handler-bind (or an abstraction based on handler-bind, such as handler-case or ignore-errors).
Active handlers can be established within the dynamic scope of other active handlers. At any point during program execution, there is a set of active handlers. When a condition is signaled, the most recent active applicable handler for that condition is selected from this set. Given a condition, the order of recentness of active applicable handlers is defined by the following two rules:
!!! Barrett: This doesn't match my reading of CSv18, p12.
I believe contradicts p21,p22 of that document. It also differs from
previous paragraph (w/ item 2) and first paragraph under "signaling".Once a handler in a handler binding form (such as handler-bind or handler-case) has been selected, all handlers in that form become inactive for the remainder of the signaling process. --------------------------------------While the selected handler runs, no other handler established by that form is active. That is, if the handler declines, no other handler established by that form will be considered for possible invocation. -----------------------------------------------------------------------------------------
The next figure shows operators relating to the handling of conditions.
handler-bind | handler-case | ignore-errors |
Figure 9–4. Operators relating to handling conditions.
When a condition is signaled, the most recent applicable active handler is invoked. Sometimes a handler will decline by simply returning without a transfer of control. In such cases, the next most recent applicable active handler is invoked.
If there are no applicable handlers for a condition that has been signaled, or if all applicable handlers decline, the condition is unhandled.
The functions cerror and error invoke the interactive condition handler (the debugger) rather than return if the condition being signaled, regardless of its type, is unhandled. In contrast, signal returns nil if the condition being signaled, regardless of its type, is unhandled.
The variable *break-on-signals* can be used to cause the debugger to be entered before the signaling process begins.
The next figure shows defined names relating to the signaling of conditions.
*break-on-signals* | error | warn |
cerror | signal |
Figure 9–5. Defined names relating to signaling conditions.
For example, a handler might legitimately signal the condition object that is its argument in order to allow outer handlers first opportunity to handle the condition. (Such a handlers is sometimes called a “default handler.”) This action is permitted because the situation which the second signaling process is addressing is really the same situation.
On the other hand, in an implementation that implemented asynchronous keyboard events by interrupting the user process with a call to signal, it would not be permissible for two distinct asynchronous keyboard events to signal identical condition objects at the same time for different Per X3J13 (at request of Gadbois). -kmp 5-Oct-93
thesituations.
!!! Barrett: Not true. Debugger may permit arbitrary returning, depending on implementation.The interactive condition handler returns only through non-local transfer of control to specially defined restarts that can be set up either by the system or by user code. Transferring control to a restart is called “invoking” the restart. Like handlers, active restarts are established dynamically, and only active restarts can be invoked. An active restart can be invoked by the user from the debugger or by a program by using invoke-restart.
!!! Barrett: :TEST predicate also affects applicability.A restart contains a function to be called when the restart is invoked, an optional name that can be used to find or invoke the restart, and an optional set of interaction information for the debugger to use to enable the user to manually invoke a restart. some optional information that allows the debugger to manage the interactive selection of the \term{restart} in situations where program handlers cannot select one.
The name of a restart is used by invoke-restart. Restarts that can be invoked only within the debugger do not need names. Useless information - terms unnamed and anonymous are never used.
\term{Restart} names provide a means
to access program interfaces
such as
\funref{find-restart} and \funref{invoke-restart}.
\term{Restarts} named
\nil\ are called ``unnamed'' or ``anonymous''
\term{restarts}. Named \term{restarts}
can be used in both
interactive and non-interactive situations, but unnamed
\term{restarts} are typically useful only in interactive situations.
Restarts can be established by using restart-bind, restart-case, and with-simple-restart. A restart function can itself invoke any other restart that was active at the time of establishment of the restart of which the function is part.
The restarts established by a restart-bind form, a restart-case form, or a with-simple-restart form have dynamic extent which extends for the duration of that form's execution.
Restarts of the same name can be ordered from least recent to most recent according to the following two rules:
If a restart is invoked but does not transfer control, the values resulting from the restart function are returned by the function that invoked the restart, either invoke-restart or invoke-restart-interactively. !!! Barrett: There are other functions that invoke restarts that we built
on these two; i.e., muffle-warning, etc.
The report function which can be specified using the
\kwd{report-function}
keyword in
\macref{restart-bind} or the
\kwd{report} keyword in \macref{restart-case},is used by a program such as the debugger to present a description of the action the restart will take. The report function is specified and established by the :report-function keyword to restart-bind or the :report keyword to restart-case. The
report function is a function of one argument, a stream on which
the output is to be done. If no report function is specified by
the user, the restart will be reported in an \term{implementation-dependent}
way.
The interactive function, which can be specified using the :interactive-function keyword to restart-bind or :interactive keyword to restart-case, is used when the restart is invoked interactively, such as from the debugger, to produce a suitable list of arguments. The function takes no arguments, and may
prompt interactively on *QUERY-IO* if necessary. The result
should be a list of arguments suitable for use in the expression
(APPLY #'INVOKE-RESTART <restart> <arguments>).
If no interactive function is specified by the user, the argument
list NIL will be assumed.
invoke-restart invokes the most recently established !!! Barrett: "active" -- :TEST could inhibit activation.restart whose name is the same as the first argument to invoke-restart. If a restart is invoked interactively by the debugger and does not transfer control but rather returns values, the precise action of the debugger on those values is implementation-defined.
!!! Barrett: This doesn't talk about supplying restart objects to INVOKE-RESTART.
KMP replaced
It is possible to define a functional interface that hides the use of
\funref{invoke-restart}. The functions \funref{abort},
\funref{continue}, \funref{muffle-warning}, \funref{store-value},
and \funref{use-value} are such interfaces.Some restarts have functional interfaces, either for syntactic
convenience or to de-emphasize the use of restarts in their
implementation.such as abort, continue, muffle-warning, store-value, and use-value. They are ordinary functions that use find-restart and invoke-restart internally, that have the same name as the restarts they manipulate, and that are provided simply for notational convenience.
The next figure shows defined names relating to restarts.
abort | invoke-restart-interactively | store-value |
compute-restarts | muffle-warning | use-value |
continue | restart-bind | with-simple-restart |
find-restart | restart-case | |
invoke-restart | restart-name |
Figure 9–6. Defined names relating to restarts.
Each restart has an associated test, which is a function of one argument (a condition or nil) which returns true if the restart should be visible in the current situation. This test is created by the :test-function option to restart-bind or the :test option to restart-case.
A restart can be “associated with” a condition explicitly by with-condition-restarts, or implicitly by restart-case. Such an assocation has dynamic extent.
A single restart may be associated with several conditions at the same time. A single condition may have several associated restarts at the same time.
Active restarts associated with a particular condition can be detected by calling a function such as find-restart, supplying that condition as the condition argument. Active restarts can also be detected without regard to any associated condition by calling such a function without a condition argument, or by supplying a value of nil for such an argument.
Date: Tue, 4 Jun 91 10:39:28 EDT From: kab@chestnut.com (Kim Barrett) To: mueller@sumex-aim.stanford.edu Cc: common-lisp@mcc.com Message-Id: <9106041439.AA08564@chestnut.com> In-Reply-To: <2884982915-12705048@KSL-EXP-30> Subject: CLEH restarts... [...] The rules for determining whether a (visible) restart is active are: 1. If the test function for the restart returns false when applied to the condition argument (which may be NIL), then the restart is inactive. 2. If testing for applicability to a specific condition (the condition argument is actually a condition object), then either a. The restart is associated with the specified condition. b. The restart is not associated with some other condition object. [This case was accidentally left out of the Version 2 proposal.] or the restart is inactive. 3. If neither of (1) and (2) indicate the restart to be inactive, then it is active. [...]
condition Condition Typewarning Condition Typestyle-warning Condition Typeserious-condition Condition Typeerror Condition Typecell-error Condition Typecell-error-name Functionparse-error Condition Typestorage-condition Condition Typeassert Macroerror Functioncerror Functioncheck-type Macrosimple-error Condition Typeinvalid-method-error Functionmethod-combination-error Functionsignal Functionsimple-condition Condition Typesimple-condition-format-control, simple-condition-format-arguments Functionwarn Functionsimple-warning Condition Typeinvoke-debugger Functionbreak Function*debugger-hook* Variable*break-on-signals* Variablehandler-bind Macrohandler-case Macroignore-errors Macrodefine-condition Macromake-condition Functionrestart System Classcompute-restarts Functionfind-restart Functioninvoke-restart Functioninvoke-restart-interactively Functionrestart-bind Macrorestart-case Macrorestart-name Functionwith-condition-restarts Macrowith-simple-restart Macroabort Restartcontinue Restartmuffle-warning Restartstore-value Restartuse-value Restartabort, continue, muffle-warning, store-value, use-value Function