[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Error Proposal #5: difficulties and suggestions
- To: Daniels.pa@Xerox.COM
- Subject: Error Proposal #5: difficulties and suggestions
- From: Kent M Pitman <KMP@SCRC-STONY-BROOK.ARPA>
- Date: Fri, 18 Apr 86 01:27 EST
- Cc: CL-Error-Handling@SU-AI.ARPA
- In-reply-to: <860416-140210-153@Xerox>
Date: 16 Apr 86 13:15 PST
From: Daniels.pa@Xerox.COM
I've just finished an implementation of the error system and would like
to share some of the things I ran across that pose a problem.
First, I believe there should be a way to set default handlers, report
methods and default tests for proceed cases other than redefining the
object in question. This isn't a big deal, but it does provide the user
some flexibility. This can cause problems if you're depending on default
handlers to ensure that SERIOUS-CONDITION ends up in the debugger if it
isn't handled, but I'd rather handle that directly in the code. That is,
ERROR always calls debug after signalling the condition and SIGNAL calls
debug after signalling if the condition is of type SERIOUS-CONDITION.
Well, it should already invoke the debugger (Moon doesn't like me to say
"calls DEBUG" because he wants to leave leeway for implementations to use
stylized entry points into the debugger other than the user's entry point)
on all conditions that are returned by the signaling process, regardless of
whether they are SERIOUS-CONDITIONs or not. Are you suggesting that we
should flush the idea of the default handler for SERIOUS-CONDITION entering
the debugger (and hence allow (SIGNAL 'a-serious-condition) to not enter
the debugger)?
The rest of the questions have to do with proceed cases. First of all,
for a given PROCEED-CASE form must the selectors be unique? I propose
that they not be. I can imagine writing a PROCEED-CASE in which
different arms with the same selector were enabled at different times by
their :TEST methods. Allowing this only adds a small complication to the
implementation of PROCEED-CASE: instead of using the proceed case name
as the selector, you need to generate a value that is carried along with
the PROCEED-CASE object that represents that arm. An integer suffices
for this.
All this would be done at a level that is invisible to the user-side of things.
I hadn't really explicitly thought about this, but don't think the proposal
was meant to have wording that precluded it. Certainly sounds like a reasonable
thing to do. In any case, it should probably go out of its way to mention that
it's ok since as you say, some obvious implementations might lead to trouble.
I'll make a note to add that.
Proceed functions appear to serve two purposes: they are a repository
for default information for that proceed type (test, report,
parameter-gathering), and they provide a simple way to find and invoke
proceed cases. These two functions are somewhat at odds with one another
when you are invoking a proceed case from an interactive debugger. In
this situation, the user has picked a particular proceed case that
should be invoked, so the obvious thing to do is call
INVOKE-PROCEED-CASE. Unfortunately, this will not use the
parameter-gathering mechanism specified in the proceed function. If
instead you see if there is a proceed function defined for that proceed
case and invoke it to get the parameter-gathering done, the proceed
function can end up invoking the wrong proceed case if there are others
with the same name that are more recently bound.
To illustrate, consider the following (somewhat contrived) code:
(define-proceed-function use-value
(v (eval (prompt-and-read "Enter expression to be EVALed: ")
)))
(block outer
(condition-bind
((foo-error
#'(lambda (condition)
(proceed-case (error 'foo-error)
(use-value (ignore x) :test true
:report "Return to inner proceed-case"
(return-from outer (values x 'inner)))))))
(proceed-case (error 'foo-error)
(use-value (ignore x) :test true
:report "Return to outer proceed-case"
(values x 'outer)))
)
)
Evaluating this will land you in the debugger with FOO-ERROR. You might
see something like:
Error FOO-ERROR.
1 - Return to inner proceed case
2 - Return to outer proceed case
Selection:
Now, the user picks selection 2. If the debugger implements proceeding
by simply invoking the given proceed case, the final values are NIL
OUTER. If the debugger instead invokes the proceed function, the user
will be prompted for a new value, say 7, and the final values will be 7
INNER. Not quite what the user asked for.
To fix this problem I propose giving proceed functions another implicit
parameter, PROCEED-CASE. If this is NIL then the proceed function
behaves as it does now: it finds the most recently bound proceed case
with that name and invokes it. If a proceed-case is supplied, it will
invoke that one specifically if it is currently enabled. It is an error
to provide a proceed case whose name differs from the proceed function.
If the proceed case is not enabled, the proceed function simply returns
NIL.
Ugh. I understand the problem. I'll have to study the syntax of
this implicit parameter idea and get back to you. I'll note just
for fun that you could do something like the following, though I
certainly wouldn't mean to imply that I intended that you do this
or that I'm not embarrassed that this is the only way out or
anything like that...
(DEFUN INVOKE-DEFAULTED-PROCEED-CASE (CASE CONDITION &REST ARGUMENTS)
(APPLY #'INVOKE-PROCEED-CASE
CASE CONDITION
(COND ((NOT (PROCEED-CASE-NAME CASE)) ;The easy case
ARGUMENTS)
(T
(LET ((FN #'(LAMBDA ()
(APPLY (PROCEED-CASE-NAME CASE)
CONDITION ARGUMENTS))))
(EVAL `(PROCEED-CASE (FUNCALL ',FN)
(,(PROCEED-CASE-NAME CASE)
(IGNORE &REST RESOLVED-ARGUMENTS)
RESOLVED-ARGUMENTS))))))))
If you agree that this would technically (if not aesthetically) solve
your problem, then we're at least talking on the same wavelength. I'll
get back to you with my thoughts on a more reasonable way around the
problem later.