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

associating restarts with conditions



Clinger> 5.  the space of condition data (the stuff stored in the
Clinger> slots of a condition)

Kelsey> I don't fully agree with number five.  Restarts are not
Kelsey> associated with particular conditions.  It is true that a
Kelsey> handler that is examing restarts got control via some
Kelsey> condition, but there is no more necessary connection
Kelsey> between the restart and that condition than between the
Kelsey> restart and the thunk whose execution raised the condition,
Kelsey> for example.

In CL, we have DEFINITELY found that it's useful to have the optional
ability to associate a condition with a restart.  I agree that it is
not an intrinsic quality of a restart, and indeed there are situations
where you can use restarts even without conditions (signaled or
otherwise).  e.g., if you press <Break> and it forces entry to the 
debugger but no condition is signaled, you might still use an ABORT
restart to go from there back to top level.  However, here's the situation
where the ability to do 
 (ASSOCIATE-RESTART-WITH-CONDITION 
    condition-to-be-signaled established-restart
    thunk)
is good:
 1. You signal an UNBOUND-VARIABLE error with a USE-VALUE restart
    available.
 2. In the handler or in an interactive debugger, another unbound variable
    occurs but NOT from a place where USE-VALUE was established.
    The handler for the inner case may say "oh, I recognize the error.
    That variable is chronically like this, but NIL is ok to use."  SO it asks
    if USE-VALUE is available and it finds one, but not with the right
    condition.

So in CL, we allow you to associate some restarts (like USE-VALUE and 
STORE-VALUE for UNBOUND-VARIABLE, or like CONTINUE for CERROR, or like
MUFFLE-WARNING for WARNING) with conditions, but others not (like ABORT).

So a typical handler might do like the following:
  (HANDLER-BIND ((UNBOUND-VARIABLE
		    #'(LAMBDA (CONDITION)
		        (LET ((R (FIND-RESTART 'USE-VALUE CONDITION)))
			  (WHEN R (INVOKE-RESTART R 42))))))
    ...)
FIND-RESTART sees all restarts when a second arg is not supplied or NIL,
and otherwise (when the second arg is a condition) sees all restarts
associated with that condition + all restarts not associated with any 
condition.

   The other four seem inevitable to me.  Number four could
   be finessed by replacing FIND-RESTARTS with:

     (find-interactive-restarts) -> list of restarts
     (find-restart restart-tag) -> restart or #f

   If more than one restart that matches <restart-tag> is
   in place, FIND-RESTART could either signal an error, or
   return the innermost or outermost.

Signaling more errors from an error handler is nearly always unwanted.
ESPECIALLY when there's nothing wrong with the situation that led to it.
In a system full of recursive functions, asking that no restart exist with
the same tag as some other on the same stack is too much.  I think you 
basically MUST tolerate multiple tags, and generally you should revel in it.
Associating some restarts with conditions where appropriate eliminates most
cases of ambigutiy I've seen.

Handling recursive errors should not put people into a panic any more
than handling nested lists should panic beginning lisp/scheme students.
The structure of things will, if you let it, help keep things straight.
It is not necessary to place a restriction on lists that their elements
should not be lists, and it ought not be necessary to say that error handling
within error handling should be any more mysterious.  But it can be if you
shy from thinking about reasonable devices to help you tell the levels apart.