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

Error Proposal #5: difficulties and suggestions



    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.