-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathcondition.tex
5790 lines (4880 loc) · 296 KB
/
condition.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%%%Chapter of Common Lisp Manual. Copyright 1989 Guy L. Steele Jr.
\clearpage\def\pagestatus{FINAL PROOF}
\def\SU#1{${}_{#1}$}
\ifx \rulang\Undef
\chapter{Conditions}
\label{CONDITION}
Author: Kent M. Pitman
This chapter presents the bulk of the Common Lisp
Condition System proposal, written by Kent~M. Pitman
and amended by X3J13. I have edited it only very lightly
to conform to the overall style of this book and have inserted a small
number of bracketed remarks identified by the initials GLS.
Please see the Acknowledgments to this second edition for the author's
acknowledgments to others who contributed to the Condition System proposal.
\noindent\hbox to \textwidth{\hss---Guy L. Steele Jr.}
\section{Introduction}
Often we find it useful to describe a function in terms of its behavior in
``normal situations.'' For example, we may say informally that the function
\cdf{+} returns the sum of its arguments or that the function
\cdf{read-char} returns the next available character on a given input
stream.
Sometimes, however, an ``exceptional situation'' will arise that does not fit
neatly into such descriptions. For example, \cdf{+} might receive an argument
that is not a number, or \cdf{read-char} might receive as a single argument
a stream that has no more available characters. This distinction between normal
and exceptional situations is in some sense arbitrary but is often very
useful in practice.
For example, suppose a function \cdf{f} were defined to allow only
integer arguments but also guaranteed to
detect and signal an error for non-integer arguments.
Such a description is in fact internally inconsistent (that is,
paradoxical) because the function's behavior is well-defined for non-integers.
Yet we would not want this annoying paradox to force description of \cdf{f}
as a function that accepts any kind of argument (just in case \cdf{f}
is being called only as a quick way to signal an error, for example).
Using the normal/exceptional distinction, we can say clearly that \cdf{f} accepts integers
in the normal situation and signals an error in exceptional situations.
Moreover, we can say that when we refer to the definition of a
function informally, it is acceptable to speak only of its normal behavior.
For example, we can speak informally about \cdf{f} as a function that accepts only
integers without feeling that we are committing some awful fraud.
Not all exceptional situations are errors. For example, a program that is
directing the typing of a long line of text may come to an end-of-line.
It is possible that no real harm will result from failing to signal end-of-line
to its caller because the operating system will simply force a carriage
return on the output device, which will continue typing on the next line. However, it
may still be interesting to establish a protocol whereby the printing program can
inform its caller of end-of-line exceptions. The caller could
then opt to deal with these situations in interesting ways at certain times.
For example, a caller might choose to terminate printing, obtaining an end-of-line
truncation. The important thing, however, is that the failure of the
caller to provide advice about the situation need not prevent
the printer program from operating correctly.
Mechanisms for dealing with exceptional situations vary widely. When an
exceptional situation is encountered, a program may attempt to handle
it by returning a distinguished value, returning an additional value,
setting a variable, calling a function, performing a special transfer of
control, or stopping the program altogether and entering the debugger.
For the most part, the facilities described in this chapter do not introduce
any fundamentally new way of dealing with exceptional situations. Rather, they
encapsulate and formalize useful patterns of data and control flow that have
been seen to be useful in dealing with exceptional situations.
A proper conceptual approach to errors should perhaps begin from first
principles, with a discussion of \emph{conditions} in general, and eventually work
up to the concept of an \emph{error} as just one of the many kinds of
conditions. However, given the primitive state of error-handling
technology, a proper buildup may be as inappropriate as requiring that a
beggar learn to cook a gourmet meal before being allowed to eat. Thus,
we deal first with the essentials---error handling---and then
go back later to fill in the missing details.
\section{Changes in Terminology}
In this section, we introduce changes to the terminology
defined in section~\ref{INTRO-ERRORS}.
A \emph{condition} is an interesting situation in a program that has been
detected and announced. Later we allow this term also to refer to
objects that programs use to represent such situations.
An \emph{error} is a condition in which normal program execution may not
continue without some form of intervention (either interactively by
the user
or under some sort of program control, as described below).
The process by which a condition is formally announced by a program is called
\emph{signaling}. The function \cdf{signal} is the primitive mechanism by which such
announcement is done. Other abstractions, such as \cdf{error} and \cdf{cerror}, are built
using \cdf{signal}.
The first edition is ambiguous about the reason why a particular program action
``is an error.'' There are two principal reasons why an action may be an error
without being required to signal an error:
\begin{itemize}
\item Detecting the error might be prohibitively expensive.
For example, \cd{(+ nil 3)} is an error. It is likely that the designers of
Common Lisp believed this would be an error in all implementations but
felt it might be excessively expensive to detect the problem
in compiled code on stock hardware, so they did not require that it signal
an error.
\item Some implementations might implement the behavior as an extension.
For example, \cd{(loop for x from 1 to 3 do (print x))} is an error because \cdf{loop}
is not defined to take atoms in its body.
In fact, however, some
implementations offer an extension that makes this well-defined. In order
to leave room for such extensions, the first edition used the ``is an error''
terminology to keep implementors from being forced to signal an error in
the extended implementations.
[This example was written well before the vote by X3J13 in January 1989
to add exactly this extension to the forthcoming draft standard
(see chapter~\ref{LOOP}).---GLS]
\end{itemize}
In this chapter, we use the following terminology.
[Compare this to the terminology presented
in section~\ref{Error-Terminology-SECTION}.---GLS]
\begin{itemize}
\item
If the signaling of a condition or error is part of a function's contract
in all situations, we say that it ``signals'' or ``must signal'' that
condition or error.
\item
If the signaling of a condition or error is optional for some important
reason (such as performance), we say that the program ``might signal''
that condition or error. In this case, we are defining the operation to be
illegal in all implementations, but allowing some implementations to fail to
detect the error.
\item
If an action is left undefined for the sake of implementation-dependent
extension, we say that it ``is undefined'' or ``has undefined effect.''
This means that it is not possible to depend portably upon the effects of
that action. A program that has undefined effect may enter the debugger,
transfer control, or modify data in unpredictable ways.
\item
In the special case where only the return value of an operation is not
well defined but any side effect and transfer-of-control behavior is
well defined, we say that it has ``undefined value.'' In this case,
the number and nature of the return values is not defined, but the
function can reasonably be expected to return. It is worth noting that
under this description, there are some (though not many) legitimate ways
in which such return value(s) can be used. For example, if the function
\cdf{foo} has no side effects and undefined value, the expression
\cd{(length (list (foo)))} is completely well defined even for portable code.
However, the effect of \cd{(print (list (foo)))} is not well defined.
\end{itemize}
\section{Survey of Concepts}
This section discusses various aspects of the condition system by topic,
illustrating them with extensive examples. The next section contains
definitions of specific functions, macros, and other facilities.
\subsection{Signaling Errors}
Conceptually, signaling an error in a program is an admission by that program
that it does not know how to continue and requires external intervention. Once
an error is signaled, any decision about how to continue must come from the
``outside.''
The simplest way to signal an error is to use the \cdf{error} function with
\cdf{format}-style arguments describing the error for the sake of the user interface.
If \cdf{error} is called and there are no active handlers (described
in sections~\ref{TRAPPING-ERRORS} and~\ref{HANDLING-CONDITIONS}), the
debugger will be entered and the error message will be typed out. For example:
\begin{lisp}
Lisp> (defun factorial (x) \\*
~~~~~~~~(cond ((or (not (typep x 'integer)) (minusp x)) \\*
~~~~~~~~~~~~~~~(error "{\Xtilde}S is not a valid argument to FACTORIAL." \\*
~~~~~~~~~~~~~~~~~~~~~~x)) \\
~~~~~~~~~~~~~~((zerop x) 1) \\
~~~~~~~~~~~~~~(t (* x (factorial (- x 1)))))) \\*
~\EV\ FACTORIAL \\
Lisp> (factorial 20) \\*
~\EV\ 2432902008176640000 \\
Lisp> (factorial -1) \\*
Error: -1 is not a valid argument to FACTORIAL. \\*
To continue, type :CONTINUE followed by an option number: \\*
~1: Return to Lisp Toplevel. \\*
Debug>
\end{lisp}
In general, a call to \cdf{error} cannot directly return. Unless special work has
been done to override this behavior, the debugger will be entered and there
will be no option to simply continue.
The only exception may be that some implementations may provide debugger
commands for interactively returning from individual stack frames; even then,
however, such commands should never be used except by someone who has read the
erring code and understands the consequences of continuing from that point. In
particular, the programmer should feel confident
about writing code like this:
\begin{lisp}
(defun wargames:no-win-scenario () \\*
~~(when (true) (error "Pushing the button would be stupid.")) \\*
~~(push-the-button))
\end{lisp}
In this scenario, there should be no chance that the function \cdf{error} will return
and the button will be pushed.
\beforenoterule
\begin{sideremark}
It should be noted that the notion of
``no chance'' that the button will be pushed is relative only to the language
model; it assumes that the language is accurately implemented. In practice,
compilers have bugs, computers have glitches, and users have been known
to interrupt at inopportune moments and use the debugger to return from
arbitrary stack frames. Such violations of the language model are
beyond the scope of the condition system but not necessarily beyond the
scope of potential failures that the programmer should consider and defend against.
The possibility of such unusual failures may of course also influence the design of
code meant to handle less drastic situations,
such as maintaining a database uncorrupted.---KMP and GLS
\end{sideremark}
\afternoterule
In some cases, the programmer may have a single, well-defined idea of a
reasonable recovery strategy for this particular error. In that case, he can
use the function \cdf{cerror}, which specifies information about what would happen
if the user did simply continue from the call to \cdf{cerror}. For example:
\begin{lisp}
Lisp> (defun factorial (x) \\*
~~~~~~~~(cond ((not (typep x 'integer)) \\*
~~~~~~~~~~~~~~~(error "{\Xtilde}S is not a valid argument to FACTORIAL." \\*
~~~~~~~~~~~~~~~~~~~~~~x)) \\
~~~~~~~~~~~~~~((minusp x) \\*
~~~~~~~~~~~~~~~(let ((x-magnitude (- x))) \\*
~~~~~~~~~~~~~~~~~(cerror "Compute -({\Xtilde}D!) instead." \\*
~~~~~~~~~~~~~~~~~~~~~~~~~"(-{\Xtilde}D)! is not defined." x-magnitude) \\*
~~~~~~~~~~~~~~~~~(- (factorial x-magnitude)))) \\
~~~~~~~~~~~~~~((zerop x) 1) \\
~~~~~~~~~~~~~~(t (* x (factorial (- x 1)))))) \\*
~\EV\ FACTORIAL \\
Lisp> (factorial -3) \\*
Error: (-3)! is not defined. \\*
To continue, type :CONTINUE followed by an option number: \\*
~1: Compute -(3!) instead. \\*
~2: Return to Lisp Toplevel. \\*
Debug> :continue 1 \\
~\EV\ -6
\end{lisp}
\subsection{Trapping Errors}
\label{TRAPPING-ERRORS}
By default, a call to \cdf{error} will force entry into the debugger. You can
override that behavior in a variety of ways. The simplest (and most blunt)
tool for inhibiting entry to the debugger on an error is to use \cdf{ignore-errors}.
In the normal situation, forms in the body of \cdf{ignore-errors} are evaluated
sequentially and the last value is returned. If a condition of type \cdf{error} is
signaled, \cdf{ignore-errors} immediately returns two values, namely \cdf{nil} and the
condition that was signaled; the debugger is not entered and no error
message is printed. For example:
\begin{lisp}
Lisp> (setq filename "nosuchfile") \\
~\EV\ "nosuchfile" \\
Lisp> (ignore-errors (open filename :direction :input)) \\
~\EV\ NIL \textrm{and} \#<FILE-ERROR 3437523>
\end{lisp}
The second return value is an object that represents the kind of error. This
is explained in greater detail in section~\ref{OBJECT-0RIENTED-BASIS}.
In many cases, however, \cdf{ignore-errors} is not desirable because it deals with
too many kinds of errors. Contrary to the belief of some, a program that
does not enter the debugger is not necessarily better than one that does.
Excessive use of \cdf{ignore-errors} may keep the program out of the debugger, but it may
not increase the program's reliability, because the program may continue
to run after encountering errors other than those you meant to work past. In
general, it is better to attempt to deal only with the particular kinds of
errors that you believe could legitimately happen. That way, if an unexpected
error comes along, you will still find out about it.
\cdf{ignore-errors} is a useful special case built from a more general facility,
\cdf{handler-case}, that allows the programmer to deal with particular kinds of
conditions (including non-error conditions) without affecting what happens
when other kinds of conditions are signaled. For example, an effect
equivalent to that of \cdf{ignore-errors} above is achieved in the following example:
\begin{lisp}
Lisp> (setq filename "nosuchfile") \\
~\EV\ "nosuchfile" \\
Lisp> (handler-case (open filename :direction :input) \\
~~~~~~~~(error (condition) \\
~~~~~~~~~~(values nil condition))) \\
~\EV\ NIL \textrm{and} \#<FILE-ERROR 3437525>
\end{lisp}
However, using \cdf{handler-case}, one can indicate a more specific condition
type than just ``error.'' Condition types are explained in detail later, but the
syntax looks roughly like the following:
\begin{lisp}
Lisp> (makunbound 'filename) \\
~\EV\ FILENAME \\
Lisp> (handler-case (open filename :direction :input) \\
~~~~~~~~(file-error (condition) \\
~~~~~~~~~~(values nil condition))) \\
Error: The variable FILENAME is unbound. \\
To continue, type :CONTINUE followed by an option number: \\
~1: Retry getting the value of FILENAME. \\
~2: Specify a value of FILENAME to use this time. \\
~3: Specify a value of FILENAME to store and use. \\
~4: Return to Lisp Toplevel. \\
Debug>
\end{lisp}
\subsection{Handling Conditions}
\label{HANDLING-CONDITIONS}
Blind transfer of control to a \cdf{handler-case} is only one possible kind
of recovery action that can be taken when a condition is signaled. The
low-level mechanism offers great flexibility in how to continue once
a condition has been signaled.
The basic idea behind condition handling is that a piece of code called the
\emph{signaler} recognizes and announces the existence of an exceptional
situation using \cdf{signal} or some function built on \cdf{signal} (such as
\cdf{error}).
The process of signaling involves the search for and invocation of a
\emph{handler}, a piece of code that will attempt to deal appropriately with
the situation.
If a handler is found, it may either \emph{handle} the situation, by performing
some non-local transfer of control, or \emph{decline} to handle it, by failing to perform a
non-local transfer of control. If it declines, other handlers are sought.
Since the lexical environment of the signaler might not be available to
handlers, a data structure called a \emph{condition} is created to represent
explicitly the relevant state of the situation. A condition either is created
explicitly using \cdf{make-condition} and then passed to a function such as \cdf{signal},
or is created implicitly by a function such as \cdf{signal} when given appropriate
non-condition arguments.
In order to handle the error, a handler is permitted to use any non-local
transfer of control such as \cdf{go} to a tag in a \cdf{tagbody},
\cdf{return} from a \cdf{block}, or
\cdf{throw} to a \cdf{catch}. In addition, structured abstractions of these
primitives are provided for convenience in exception handling.
A handler can be made dynamically accessible to a program by use of
\cdf{handler-bind}. For example, to create a handler for a condition of type
\cdf{arithmetic-error}, one might write:
\begingroup
\makeatletter
\def\@listi{\leftmargin\leftmargini \labelsep\leftmargin
\parsep 3pt\relax
\topsep 4pt plus 9pt\relax
\itemsep\topsep}
\makeatother
\begin{lisp}
(handler-bind ((arithmetic-error \emph{handler}))\emph{body})
\end{lisp}
The handler is a function of one argument, the condition. If a condition of
the designated type is signaled while the \emph{body} is executing (and there are no
intervening handlers), the handler would be invoked on the given condition,
allowing it the option of transferring control. For example, one might write a
macro that executes a body, returning either its value(s) or the two values
\cdf{nil} and the condition:
\begin{lisp}
(defmacro without-arithmetic-errors (\&body forms) \\
~~(let ((tag (gensym))) \\
~~~~`(block ,tag \\
~~~~~~ (handler-bind ((arithmetic-error \\
~~~~~~~~~~~~~~~~~~~~~~~~~\#'(lambda (c)~~~~~;\textrm{Argument \cdf{c} is a condition} \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (return-from ,tag (values nil c))))) \\
~~~~~~~~~,@body)))) \\
\end{lisp}
\endgroup
The handler is executed in the dynamic context of the signaler, except
that the set of available condition handlers will have been rebound to
the value that was active at the time the condition handler was made
active. If a handler decline (that is, it does not transfer control), other
handlers are sought. If no handler is found and the condition was signaled
by \cdf{error} or \cdf{cerror} (or some function such as \cdf{assert} that behaves like
these functions), the debugger is entered, still in the dynamic context
of the signaler.
\subsection{Object-Oriented Basis of Condition Handling}
\label{OBJECT-0RIENTED-BASIS}
Of course, the ability of the handler to usefully handle an exceptional
situation is related to the quality of the information it is provided. For
example, if all errors were signaled by
\begin{lisp}
(error "\emph{some format string}")
\end{lisp}
then the only piece of information that would be accessible to the handler
would be an object of type \cdf{simple-error} that had a slot containing the
format string.
If this were done, \cdf{string-equal} would be the preferred way to tell one error
from another, and it would be very hard to allow flexibility in the
presentation of error messages because existing handlers would tend to be
broken by even tiny variations in the wording of an error message. This
phenomenon has been the major failing of most error systems previously
available in Lisp. It is fundamentally important to decouple the error
message string (the human interface) from the objects that formally
represent the error state (the program interface). We therefore have the
notion of typed conditions, and of formal operations on those conditions
that make them inspectable in a structured way.
This object-oriented approach to condition handling has the following
important advantages over a text-based approach:
\begin{itemize}
\item
Conditions are classified according to subtype relationships, making
it easy to test for categories of conditions.
\item
Conditions have named slot values through which parameters are conveyed
from the program that signals the condition to the program that handles it.
\item
Inheritance of methods and slots reduces the amount of explicit
specification necessary to achieve various interesting effects.
\end{itemize}
Some condition types are defined by this document, but the set of
condition types is extensible using \cdf{define-condition}.
Common Lisp condition types are in fact CLOS classes, and condition objects
are ordinary CLOS objects; \cdf{define-condition} merely
provides an abstract interface that is a bit more convenient than
\cdf{defclass} for defining conditions.
Here, as an example,
we define a two-argument function called \cdf{divide} that is patterned after
the \cdf{/} function but does some stylized error checking:
\begin{lisp}
(defun divide (numerator denominator) \\
~~(cond ((or (not (numberp numerator)) \\
~~~~~~~~~~~~~(not (numberp denominator))) \\
~~~~~~~~~(error "(DIVIDE '{\Xtilde}S '{\Xtilde}S) - Bad arguments." \\
~~~~~~~~~~~~~~~~numerator denominator)) \\
~~~~~~~~((zerop denominator) \\
~~~~~~~~~(error 'division-by-zero \\
~~~~~~~~~~~~~~~~:operator 'divide \\
~~~~~~~~~~~~~~~~:operands (list numerator denominator))) \\
~~~~~~~~(t ...)))
\end{lisp}
Note that in the first clause we have used \cdf{error} with a string argument
and in the second clause we have named a particular condition type,
\cdf{division-by-zero}. In the case of a string argument, the condition type that
will be signaled is \cdf{simple-error}.
The particular kind of error that is signaled may be important
in cases where handlers are active. For example, \cdf{simple-error} inherits
from type \cdf{error}, which in turn inherits from type \cdf{condition}. On the
other hand, \cdf{division-by-zero} inherits from \cdf{arithmetic-error}, which
inherits from \cdf{error}, which inherits from \cdf{condition}. So if a handler
existed for \cdf{arithmetic-error} while a \cdf{division-by-zero} condition was
signaled, that handler would be tried; however, if a \cdf{simple-error}
condition were signaled in the same context, the handler for type
\cdf{arithmetic-error} would not be tried.
\subsection{Restarts}
\label{RESTARTS}
The Common Lisp Condition System creats a clear
separation between the act of signaling an error of a particular type and the
act of saying that a particular way of recovery is appropriate. In the \cdf{divide}
example above, simply signaling an error does not imply a willingness on the
part of the signaler to cooperate in any corrective action. For example, the
following sample interaction illustrates that the only recovery action
offered for this error is ``Return to Lisp Toplevel'':
\begin{lisp}
Lisp> (+ (divide 3 0) 7) \\
Error: Attempt to divide 3 by 0. \\
To continue, type :CONTINUE followed by an option number: \\
~1: Return to Lisp Toplevel. \\
Debug> :continue 1 \\
Returned to Lisp Toplevel. \\
Lisp>
\end{lisp}
When an error is detected and the function \cdf{error} is called, execution cannot
continue normally because \cdf{error} will not directly return. Control can be
transferred to other points in the program, however, by means of specially
established ``restarts.''
\subsection{Anonymous Restarts}
The simplest kind of restart involves structured transfer of control using
a macro called \cdf{restart-case}. The \cdf{restart-case} form allows execution of
a piece of code in a context where zero or more restarts are active, and
where if one of those restarts is ``invoked,'' control will be transferred
to the corresponding clause in the \cdf{restart-case} form. For example, we could
rewrite the previous \cdf{divide} example as follows.
\begin{lisp}
(defun divide (numerator denominator) \\
~~(loop \\
~~~~(restart-case \\
~~~~~~~~(return \\
~~~~~~~~~~(cond ((or (not (numberp numerator)) \\
~~~~~~~~~~~~~~~~~~~~~(not (numberp denominator))) \\
~~~~~~~~~~~~~~~~~(error "(DIVIDE '{\Xtilde}S '{\Xtilde}S) - Bad arguments." \\
~~~~~~~~~~~~~~~~~~~~~~~~~numerator denominator)) \\
~~~~~~~~~~~~~~~~((zerop denominator) \\
~~~~~~~~~~~~~~~~~(error 'division-by-zero \\
~~~~~~~~~~~~~~~~~~~~~~~~:operator 'divide \\
~~~~~~~~~~~~~~~~~~~~~~~~:operands (list numerator denominator))) \\
~~~~~~~~~~~~~~~~(t ...))) \\
~~~~~~(nil (arg1 arg2) \\
~~~~~~~~~~:report "Provide new arguments for use by DIVIDE." \\
~~~~~~~~~~:interactive \\
~~~~~~~~~~~~(lambda () \\
~~~~~~~~~~~~~~~(list (prompt-for 'number "Numerator: ") \\
~~~~~~~~~~~~~~~~~~~~~(prompt-for 'number "Denominator: "))) \\
~~~~~~~~(setq numerator arg1 denominator arg2)) \\
~~~~~~(nil (result) \\
~~~~~~~~~~:report "Provide a value to return from DIVIDE." \\
~~~~~~~~~~:interactive \\
~~~~~~~~~~~~(lambda () (list (prompt-for 'number "Result: "))) \\
~~~~~~~~(return result)))))
\end{lisp}
\beforenoterule
\begin{sideremark}
The function \cdf{prompt-for} used in this chapter in a number of places is
not a part of Common Lisp. It is used in the examples in this chapter only to keep
the presentation simple. It is assumed to accept a type specifier
and optionally a format string and associated arguments. It uses the
format string and associated arguments as part of an interactive prompt,
and uses \cdf{read} to read a Lisp object; however, only an object of the
type indicated by the type specifier is accepted.
The question of whether or not \cdf{prompt-for} (or something like it) would be a
useful addition to Common Lisp is under consideration by X3J13, but as of
January 1989 no action has been taken. In spite of its use in a number of examples,
nothing in the Common Lisp Condition System depends on this function.
\end{sideremark}
\afternoterule
In the example, the \cdf{nil} at the head of each clause
means that it is an ``anonymous'' restart.
Anonymous restarts are typically invoked only from within the
debugger. As we shall see later, it is possible to have ``named restarts''
that may be invoked from code without the need for user intervention.
If the arguments to anonymous restarts are not optional, then special
information must be provided about what the debugger should use as arguments.
Here the \cd{:interactive} keyword is used to specify that information.
The \cd{:report} keyword introduces information to be used when presenting the
restart option to the user (by the debugger, for example).
Here is a sample interaction that takes advantage of the restarts provided
by the revised definition of \cdf{divide}:
\begin{lisp}
Lisp> (+ (divide 3 0) 7) \\
Error: Attempt to divide 3 by 0. \\
To continue, type :CONTINUE followed by an option number: \\
~1: Provide new arguments for use by the DIVIDE function. \\
~2: Provide a value to return from the DIVIDE function. \\
~3: Return to Lisp Toplevel. \\
Debug> :continue 1 \\
1 \\
Numerator: 4 \\
Denominator: 2 \\
~\EV\ 9
\end{lisp}
\subsection{Named Restarts}
In addition to anonymous restarts, one can have named restarts, which can be invoked
by name from within code. As a trivial example, one could write
\begin{lisp}
(restart-case (invoke-restart 'foo 3) \\
~~(foo (x) (+ x 1)))
\end{lisp}
to add \cd{3} to \cd{1}, returning \cd{4}. This trivial example is conceptually analogous to
writing:
\begin{lisp}
(+ (catch 'something (throw 'something 3)) 1)
\end{lisp}
For a more realistic example, the code for the function \cdf{symbol-value} might signal an
unbound variable error as follows:
\begin{lisp}
(restart-case (error "The variable {\Xtilde}S is unbound." variable) \\*
~~(continue () \\*
~~~~~~:report \\*
~~~~~~~~(lambda (s)~~~~~;\textrm{Argument \cdf{s} is a stream} \\*
~~~~~~~~~~(format s "Retry getting the value of {\Xtilde}S." variable)) \\*
~~~~(symbol-value variable)) \\
~~(use-value (value) \\*
~~~~~~:report \\*
~~~~~~~~(lambda (s)~~~~~;\textrm{Argument \cdf{s} is a stream} \\*
~~~~~~~~~~(format s "Specify a value of {\Xtilde}S to use this time." \\*
~~~~~~~~~~~~~~~~~~variable)) \\*
~~~~value) \\
~~(store-value (value) \\*
~~~~~~:report \\*
~~~~~~~~(lambda (s)~~~~~;\textrm{Argument \cdf{s} is a stream} \\*
~~~~~~~~~~(format s "Specify a value of {\Xtilde}S to store and use." \\*
~~~~~~~~~~~~~~~~~~variable)) \\*
~~~~(setf (symbol-value variable) value) \\*
~~~~value))
\end{lisp}
If this were part of the implementation of \cdf{symbol-value}, then it would be possible
for users to write a variety of automatic handlers for unbound variable
errors. For example, to make unbound variables evaluate to themselves, one
might write
\begin{lisp}
(handler-bind ((unbound-variable \\
~~~~~~~~~~~~~~~~~\#'(lambda (c)~~~~~;\textrm{Argument \cdf{c} is a condition} \\
~~~~~~~~~~~~~~~~~~~~~(when (find-restart 'use-value) \\
~~~~~~~~~~~~~~~~~~~~~~~(invoke-restart 'use-value \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(cell-error-name c)))))) \\
~~\emph{body})
\end{lisp}
\subsection{Restart Functions}
For commonly used restarts, it is conventional to define a program interface
that hides the use of \cdf{invoke-restart}. Such program interfaces to restarts
are called \emph{restart functions}.
The normal convention is for the function to share the name of the restart.
The pre-defined functions \cdf{abort}, \cdf{continue}, \cdf{muffle-warning}, \cdf{store-value}, and
\cdf{use-value} are restart functions. With \cdf{use-value} the above example of
\cdf{handler-bind} could have been written more concisely as
\begin{lisp}
(handler-bind ((unbound-variable \\
~~~~~~~~~~~~~~~~~~~\#'(lambda (c)~~~~~;\textrm{Argument \cdf{c} is a condition} \\
~~~~~~~~~~~~~~~~~~~~~~~(use-value (cell-error-name c))))) \\
~~\emph{body})
\end{lisp}
\subsection{Comparison of Restarts and Catch/Throw}
One important feature that \cdf{restart-case} (or \cdf{restart-bind}) offers that
\cdf{catch} does not is the ability to reason about the available points to
which control might be transferred without actually attempting the
transfer. One could, for example, write
\begin{lisp}
(ignore-errors (throw ...))
\end{lisp}
which is a sort of poor man's variation of
\begin{lisp}
(when (find-restart 'something) \\*
~~(invoke-restart 'something))
\end{lisp}
but there is no way to use \cdf{ignore-errors} and \cdf{throw} to simulate something
like
\begin{lisp}
(when (and (find-restart 'something) \\*
~~~~~~~~~~~(find-restart 'something-else)) \\*
~~(invoke-restart 'something))
\end{lisp}
or even just
\begin{lisp}
(when (and (find-restart 'something) \\
~~~~~~~~~~~(yes-or-no-p "Do something? ")) \\
~~(invoke-restart 'something))
\end{lisp}
because the degree of inspectability that comes with simply writing
\begin{lisp}
(ignore-errors (throw ...))
\end{lisp}
is too primitive---getting the desired information also forces
transfer of control, perhaps at a time when it is not desirable.
Many programmers have previously evolved strategies like the following
on a case-by-case basis:
\begin{lisp}
(defvar *foo-tag-is-available* nil) \\
\\
(defun fn-1 () \\
~~(catch 'foo \\
~~~~(let ((*foo-tag-is-available* t)) \\
~~~~~~... (fn-2) ...))) \\
\\
(defun fn-2 () \\
~~... \\
~~(if *foo-tag-is-available* (throw 'foo t)) \\
~~...)
\end{lisp}
The facility provided by \cdf{restart-case} and \cdf{find-restart} is intended to
provide a standardized protocol for this sort of information to be
communicated between programs that were developed independently so that
individual variations from program to program
do not thwart the overall modularity and debuggability of programs.
Another difference between the restart facility and the \cdf{catch}/\cdf{throw}
facility is that a \cdf{catch} with any given tag completely shadows any
outer pending \cdf{catch} that uses the same tag. Because of the presence
of \cdf{compute-restarts}, however, it is possible to see shadowed restarts,
which may be very useful in some situations (particularly in an
interactive debugger).
\subsection{Generalized Restarts}
\label{LAST-RESTARTS-SECTION}
\cdf{restart-case} is a mechanism that allows only imperative transfer of control
for its associated restarts. \cdf{restart-case} is built on a lower-level mechanism
called \cdf{restart-bind}, which does not force transfer of control.
\cdf{restart-bind} is to \cdf{restart-case} as \cdf{handler-bind} is to
\cdf{handler-case}.
The syntax is
\begin{lisp}
(restart-bind ((\emph{name} \emph{function} . \emph{options})) . \emph{body})
\end{lisp}
The \emph{body} is executed in a dynamic context within which the \emph{function}
will be called whenever
\cd{(invoke-restart '\emph{name})} is executed. The \emph{options} are keyword-style and are
used to pass information such as that provided with the
\cd{:report} keyword in \cdf{restart-case}.
A \cdf{restart-case} expands into a call to \cdf{restart-bind} where the function
simply does an unconditional transfer of control to a particular body
of code, passing along ``argument'' information in a structured way.
It is also possible to write restarts that do not transfer control. Such
restarts may be useful in implementing various special commands for the
debugger that are of interest only in certain situations. For example,
one might imagine a situation where file space was exhausted and the
following was done in an attempt to free space in directory \cdf{dir}:
\begin{lisp}
(restart-bind ((nil \#'(lambda () (expunge-directory dir)) \\
~~~~~~~~~~~~~~~~~~~~:report-function \\
~~~~~~~~~~~~~~~~~~~~~~\#'(lambda (stream) \\
~~~~~~~~~~~~~~~~~~~~~~~~~~(format stream "Expunge {\Xtilde}A." \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(directory-namestring dir))))) \\
~~(cerror "Try this file operation again." \\
~~~~~~~~~~'directory-full :directory dir))
\end{lisp}
In this case, the debugger might be entered and the user could first
perform the expunge (which would not transfer control from the debugger
context) and then retry the file operation:
\begin{lisp}
Lisp> (open "FOO" :direction :output) \\
Error: The directory PS:<JDOE> is full. \\
To continue, type :CONTINUE followed by an option number: \\
~1: Try this file operation again. \\
~2: Expunge PS:<JDOE>. \\
~3: Return to Lisp Toplevel. \\
Debug> :continue 2 \\
Expunging PS:<JDOE> ... 3 records freed. \\
Debug> :continue 1 \\
~\EV\ \#<OUTPUT-STREAM "PS:<JDOE>FOO.LSP" 2323473>
\end{lisp}
\subsection{Interactive Condition Handling}
When a program does not know how to continue, and no active handler is able to
advise it, the ``interactive condition handler,'' or ``debugger,'' can be
entered. This happens implicitly through the use of functions such as \cdf{error}
and \cdf{cerror}, or explicitly through the use of the function
\cdf{invoke-debugger}.
The interactive condition handler never returns directly; it returns only
through structured non-local transfer of control to specially defined restart
points that can be set up either by the system or by user code. The
mechanisms that support the establishment of such structured restart points
for portable code are outlined
in sections~\ref{RESTARTS} through~\ref{LAST-RESTARTS-SECTION}.
Actually, implementations may also provide extended debugging facilities that
allow return from arbitrary stack frames. Although such commands are frequently
useful in practice, their effects are implementation-dependent because they
violate the Common Lisp program abstraction. The effect of using such
commands is undefined with respect to Common Lisp.
\subsection{Serious Conditions}
The \cdf{ignore-errors} macro will trap conditions of type \cdf{error}. There are,
however, conditions that are not of type \cdf{error}.
Some conditions are not considered errors but are still very serious, so
we call them \emph{serious conditions} and we use the type \cdf{serious-condition} to
represent them. Conditions such as those that might be signaled for
``stack overflow'' or ``storage exhausted'' are in this category.
The type \cdf{error} is a subtype of \cdf{serious-condition}, and it would technically
be correct to use the term ``serious condition'' to refer to all serious
conditions whether errors or not. However, normally we use the term
``serious condition'' to refer to things of type \cdf{serious-condition} but not
of type \cdf{error}.
The point of the distinction between errors and other serious conditions
is that some conditions are known to occur for reasons that are beyond the
scope of Common Lisp to specify clearly. For example, we know that a stack
will generally be used to implement function calling, and we know that stacks
tend to be of finite size and are prone to overflow. Since the available
stack size may vary from implementation to implementation, from session
to session, or from function call to function call, it would be confusing
to have expressions such as \cd{(ignore-errors (+~a~b))} return a number sometimes
and \cdf{nil} other times if \cdf{a} and \cdf{b} were always bound to numbers and the stack
just happened to overflow on a particular call. For this reason, only
conditions of type \cdf{error} and not all conditions of type \cdf{serious-condition}
are trapped by \cdf{ignore-errors}. To trap other conditions, a lower-level
facility must be used (such as \cdf{handler-bind} or \cdf{handler-case}).
By convention, the function \cdf{error} is preferred over \cdf{signal} to signal conditions
of type \cdf{serious-condition} (including those of type \cdf{error}). It is the use of
the function \cdf{error}, and not the type of the condition being signaled, that
actually causes the debugger to be entered.
\subsection{Non-Serious Conditions}
Some conditions are neither errors nor serious conditions. They are signaled
to give other programs a chance to intervene, but if no action is taken,
computation simply continues normally.
For example, an implementation might choose to signal a non-serious (and
implementation-dependent) condition
called \cdf{end-of-line} when output reaches the last character position on a line
of character output. In such an implementation, the signaling of this
condition might allow a convenient way for other programs to intervene,
producing output that is truncated at the end of a line.
By convention, the function \cdf{signal} is used to signal conditions that are not
serious. It would be possible to signal serious conditions using \cdf{signal}, and
the debugger would not be entered if the condition went unhandled. However,
by convention,
handlers will generally tend to assume that serious conditions and errors
were signaled by calling the \cdf{error} function (and will therefore
force entry to the interactive condition handler) and that they should
work to avoid this.
\subsection{Condition Types}
Some types of conditions are predefined by the system. All types of conditions
are subtypes of \cdf{condition}. That is, \cd{(typep~\emph{x} 'condition)} is true if
and only if the value of \emph{x} is a condition.
Implementations supporting multiple (or non-hierarchical) type inheritance
are expressly permitted to exploit multiple inheritance in the tree of
condition types as implementation-dependent extensions, as long as such
extensions are compatible with the specifications in this chapter.
[X3J13 voted in March 1989 \issue{ZLOS-CONDITIONS}
to integrate the Condition System and the Object System,
so multiple inheritance is always available for condition types.---GLS]
In order to avoid problems in portable code that runs both in systems with
multiple type inheritance and in systems without it, programmers are explicitly
warned that while all correct Common Lisp implementations will ensure that
\cd{(typep~\emph{c} 'condition)}
is true for all conditions \emph{c} (and all subtype relationships indicated in this
chapter will also be true), it should \emph{not} be assumed that two condition
types specified to be subtypes of the same third type are disjoint.
(In some cases,
disjoint subtypes are identified explicitly, but such disjointness is not to be assumed by
default.) For example, it follows from the subtype descriptions contained in
this chapter that in all implementations
\cd{(typep~\emph{c}~'control-error)} implies \cd{(typep~\emph{c}~'error)},
but note that
\cd{(typep~\emph{c}~'control-error)} does \emph{not}
imply \cd{(not~(typep~\emph{c}~'cell-error))}.
\subsection{Signaling Conditions}
When a condition is signaled, the system tries to locate the most appropriate
handler for the condition and to invoke that handler.
Handlers are established dynamically using \cdf{handler-bind} or abstractions built
on \cdf{handler-bind}.
If an appropriate handler is found, it is called. In some circumstances,
the handler may \emph{decline} simply by returning without performing a
non-local transfer of control. In such cases, the search for an
appropriate handler is picked up where it left off, as if the called
handler had never been present.
If no handler is found, or if all handlers that were found decline,
\cdf{signal} returns \cdf{nil}.
Although it follows from the description above, it is perhaps worth noting
explicitly that the lookup procedure described here will prefer a general
but more (dynamically) local handler over a specific but less (dynamically)
local handler. Experience with existing condition systems suggests that
this is a reasonable approach and works adequately in most situations.
Some care should be taken when binding handlers for very general kinds of
conditions, such as is done in \cdf{ignore-errors}. Often, binding for a more
specific condition type than \cdf{error} is more appropriate.
\subsection{Resignaling Conditions}
[The contents of this section are still a subject of some debate within X3J13.
The reader may wish to take this section with a grain of salt.---GLS]
Note that signaling a condition has no side effect on that condition, and
that there is no dynamic state contained in a condition object. As such, it
may at times be reasonable and appropriate to consider caching condition
objects for repeated use, re-signaling conditions from within handlers,
or saving conditions away somewhere and re-signaling them later.
For example, it may be desirable for the system to pre-allocate objects of type
\cdf{storage-condition} so that they can be signaled when needed without
attempting to allocate more storage.
\subsection{Condition Handlers}
\label{CONDITION-HANDLERS}
A \emph{handler} is a function of one argument, the condition to be handled. The
handler may inspect the object
to be sure it is ``interested'' in handling the condition.
A handler is executed in the dynamic context of the signaler, except that the
set of available condition handlers will have been rebound to the value that
was active at the time the condition handler was made active. The intent of
this is to prevent infinite recursion because of errors in a condition handler.
After inspecting the condition, the handler should take one of the following
actions:
\begin{itemize}
\item
It might \emph{decline} to handle the condition (by simply returning). When
this happens, the returned values are ignored and the effect is the same
as if the handler had been invisible to the mechanism seeking to find a
handler. The next handler in line will be tried, or if no such handler
exists, the condition will go unhandled.
\item
It might \emph{handle} the condition (by performing some non-local transfer
of control). This may be done either primitively using \cdf{go}, \cdf{return}, or \cdf{throw},
or more abstractly using a function such as \cdf{abort} or \cdf{invoke-restart}.
\item
It might signal another condition.
\item
It might invoke the interactive debugger.
\end{itemize}
In fact, the latter two actions (signaling another condition or entering the
debugger) are really just ways of putting off the decision to either handle
or decline, or trying to get someone else to make such a decision. Ultimately,
all a handler can do is to handle or decline to handle.
\subsection{Printing Conditions}
When \cdf{*print-escape*} is \cdf{nil} (for example,
when the \cdf{princ} function or the \cd{{\Xtilde}A}
directive is used with \cdf{format}), the report method for the condition will be invoked. This will
be done automatically by functions such as \cdf{invoke-debugger}, \cdf{break}, and \cdf{warn},
but there may still be situations in which it is desirable to have a
condition report under explicit user control. For example,
\begin{lisp}
(let ((form '(open "nosuchfile"))) \\
~~(handler-case (eval form) \\
~~~~(serious-condition (c) \\
~~~~~~(format t "{\Xtilde}\&Evaluation of {\Xtilde}S failed:{\Xtilde}\%{\Xtilde}A" form c))))
\end{lisp}
might print something like
\begin{lisp}
Evaluation of (OPEN "nosuchfile") failed: \\
The file "nosuchfile" was not found.
\end{lisp}
Some suggestions about the form of text typed by report methods:
\begin{itemize}
\item
The message should generally be a complete sentence, beginning with a
capital letter and ending with appropriate punctuation (usually a period).
\item
The message should \emph{not} include any introductory text such as ``\cd{Error:}''
or ``\cd{Warning:}'' and should not be followed by a trailing newline. Such
text will be added as may be appropriate to context by the routine invoking
the report method.
\item
Except where unavoidable, the tab character (which is only semi-standard anyway)
should not be used in
error messages. Its effect may vary from one implementation to another and may
cause problems even within an implementation because it may do different
things depending on the column at which the error report begins.
\item
Single-line messages are preferred, but newlines in the middle of long
messages are acceptable.
\item
If any program (for example, the debugger) displays messages indented from the
prevailing left margin (for example, indented seven spaces because they
are prefixed by the seven-character herald ``\cd{Error:~}''), then that program
will take care of inserting the appropriate indentation into the extra
lines of a multi-line error message. Similarly, a program that prefixes
error messages with semicolons so that they appear to be comments should
take care of inserting a semicolon at the beginning of each line in a
multi-line error message. (These rules are important because, even within