[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
What happens when no handler is found?
- To: cl-error-handling@SU-AI.ARPA
- Subject: What happens when no handler is found?
- From: Kent M Pitman <KMP@SCRC-STONY-BROOK.ARPA>
- Date: Mon, 6 Jan 86 17:36 EST
- Cc: kmp@SCRC-STONY-BROOK.ARPA, Moon@SCRC-STONY-BROOK.ARPA
- In-reply-to: <8601050031.AA00437@gswd-vms.ARPA>
I might as well take this opportunity to mention that Moon has been
studying the proposal that I presented at the meeting and is in the
process of negotiating a variation of that with me. Richard Mlynarik
(MLY@MIT-MC) has also passed along some comments which are being
considered in that revision. We'll be sending out a revised proposal and
accompanying sample implementation as soon as we're satisfied internally
here. It shouldn't be too much longer. Sorry for the delay; this is a
high priority item for us (as I'm sure it is for others on this list).
The rest of this message is a reply to marick@gswd-vms about
Date: Sat, 4 Jan 86 18:31:03 CST
From: marick@gswd-vms (Brian Marick)
Subject: What happens when no handler is found?
Comment: Remailed at SU-AI after delay caused by distribution list error.
A comment on Kent Pitman's error-handling proposal: (Reposting)
Having SIGNAL return NIL if no handler is found makes me nervous;
it seems to assume that people will explicitly plan for the case where
no handler is found, whereas I expect many people will create bugs
because they implicitly assume that their condition will be handled.
And even if detecting the case of a missing handler by checking whether
SIGNAL returns is OK, that doesn't work with SIGNAL-CASE, which is
expected to return and may return any value.
I think you're just confusing an "error" with a "condition". Not all
conditions are errors. You can think of a condition as being anything
exceptional. For example, if you're working on a clerical task and you
note something "unusual", you might remark it aloud to your boss and
s/he might or might not care. If s/he did not, you wouldn't dwell on it,
you'd just go on. An error, on the other hand, is something that stops
your work and that you can't proceed on without external intervention.
There are plenty more things that you might "remark about" than there
are that you might "stall over". For example, if you worked at Walt
Disney World and the 1,000,000th person walked through the turnstyles,
you might want to make a fuss over him but it wouldn't be an error not
to. This kind of planned ignorability of nevertheless interesting
information is not in error and is still quite useful. It is
underexploited today only because the right tools for playing with it
have not existed until recently.
There's a distinction between code that's sending a signal to ask
for help and code that's sending a signal because there's nothing
left for it to do, no matter what. How that distinction meshes with
the definitions of SIGNAL, SIGNAL-CASE, ERROR, and ERROR-CASE is
not clear enough.
SIGNAL and SIGNAL-CASE do not ask for help. They allow an opportunity
for it. In a way, ERROR and ERROR-CASE do ask for help. More properly,
though, they simply announce that without help there is nothing more
that will get done in the current computation.
How if their definitions are modified/clarified to say
SIGNAL -- control never resumes in the signalling function. It is an
error (with type NO-SUCH-HANDLER or whatever) for no handler to be found.
Signal is not only for errors. It is for any unusual event. Not all
unusual events need to be handled. If you don't subscribe to that idea,
then you should never use SIGNAL and always use ERROR and you'll be all
Examples of things that are not errors but which might want to be
* QUERY -- You might want a query routine which always did a
(non-fatal) signal saying that a query was about to happen. One
way to proceed from such a query (after inspecting any relevant
data) might be by saying what the query should be without entering a
mode requiring actual I/O. This could be useful in various batch
applications. It is not necessarily an error to not handle such a
condition. You'd just fall through to other code which would interact
at the terminal.
* DEGENERATE CASES -- Consider a function PPRINT* which took a list of
things and pretty printed them to a given stream. Interactively at
the console, in home-grown environment-saving programs, or whatever,
it might be fine for (PPRINT* L) to quietly print nothing when L was
bound to (). Yet for someapplications, it might be useful to notice
that nothing had been printed. One way to do this would be for PPRINT*
to signal a non-fatal exception when it saw an empty list and to assume
that if no one handled that exception and took control of things that
it was OK to proceed.
* HOOKS -- For example, the Mode hooks which are so popular in MIT's
Emacs are an example of something that could be implemented as a
non-fatal condition. The program says "I'm selecting Text Mode now"
and the handler says "Wait, I'm glad you mentioned that because I
have code to run." Had there been no handler, it is still reasonable
to proceed and select Text Mode.
* WARNINGS -- The break-on-warnings feature is something which is an
example of something which could neatly be handled by non-fatal
conditions. Normally, if WARN is called, you can set a variable saying
that a breakpoint should be created. However, another way this (or similar
mechanisms) could be implemented would be for WARN to signal a non-fatal
condition and to allow people arbitrary control at the time of the WARN.
This would allow hooks so that one didn't have to have variables like
*abort-on-warnings*, *beep-on-warnings*, etc. to allow every possible
kind of customization. Instead, one would just write:
#'(lambda (cond) (ignore cond) (abort))))
or whatever was needed to handle a specific situation in a very general
way. If no such condition-bind had been done, the default would be to
simply continue with the normal I/O done by the WARN routine.
It's fairly easy to conjure examples of places where things like this
can be used. People who have never used the Lisp Machine condition
system probably don't have the experience to realize the importance of
this sort of thing. Most Lisp Machine users don't even realize the
flexibility at their disposal in this regard, though that is changing. I
and a few other people I know have used this feature to great advantage.
SIGNAL-CASE -- by default, it is an error (as above) for no handler
to be found. If one of the clauses of the SIGNAL-CASE is headed by
:NO-HANDLER (or a list containing :NO-HANDLER), that the body of
that clause is invoked.
This is an interesting idea but I'm a little worried because it blurs
two notions that I am not sure should be blurred. The first is "how to
proceed a certain way" which is what the kind of clauses I'm proposing
do. The second, which you're proposing, is essentially a shorthand for
condition-bind, which doesn't describe how to proceed but rather
describes how to select how to proceed. For example, under your proposal
you could logically imagine writing a :NO-HANDLER clause which wanted to
proceed using one of the proceed cases in another of the clauses. I'm
not sure if it's wise to invite that sort of confusion.
ERROR -- control never resumes in the signalling function. If no
handler is found, the signalled condition is passed to the debugger.
(The distinction between this and SIGNAL is that the error reported
to the user is what was discovered by the program, not by the
I'm not sure what this distinction means. There are no "error systems"
that are not programs. Also, the issue of "reporting" is a kind of
"handling" and is completely logically distinct from the issue of
ERROR-CASE -- just like now. A :NO-HANDLER clause makes no sense here.