From: Simon Andr�s
Subject: handler-case vs handler-bind
Date: 
Message-ID: <vcdzno7nnc2.fsf@tarski.math.bme.hu>
As part of an effort to make myself more comfortable with the
condition system, I'm trying to understand the difference between
handler-case and handler-bind.  The following list is what I came up
with. I wonder if it's correct and exhaustive.

1. handler-bind takes forms (as an implicit progn), handler-case takes
   only one form

2. the error-clauses have different forms: with handler-bind, they are
   functions of one variable, with handler-case, they're, in effect,
   restricted to being anonymous functions

3. handler-case can take a :no-error error-clause.

If the form(s) signal(s) a condition, then 

4. if an applicable error-clause declines, handler-bind tries the
   rest, handler-case does not

5. handler-case returns the result of the applicable error-clause,
   handler-bind does not return anything

Am I right that no. 4 is the only non-trivial difference? And that
this feature of handler-bind could be simulated by nested
handler-cases, as in

(defmacro my-handler-bind (clauses &body forms)
  (let ((call `(progn ,@forms)))
    (dolist (clause clauses)
      (setf call
	`(handler-case ,call
	   (,(car clause) (cond)
	     (progn
	       (funcall ,(cadr clause) cond)
	       (signal cond))))))
    call))

Andras

From: Kaz Kylheku
Subject: Re: handler-case vs handler-bind
Date: 
Message-ID: <cf333042.0303071112.9ce8326@posting.google.com>
······@math.bme.hu (Simon Andr�s) wrote in message news:<···············@tarski.math.bme.hu>...
> As part of an effort to make myself more comfortable with the
> condition system, I'm trying to understand the difference between
> handler-case and handler-bind.  The following list is what I came up
> with. I wonder if it's correct and exhaustive.
> 
> 1. handler-bind takes forms (as an implicit progn), handler-case takes
>    only one form

That's only a superficial syntactic difference. You could make a macro
for HANDLER-BIND which makes the syntax look like HANDLER-CASE without
changing the semantics.

> 2. the error-clauses have different forms: with handler-bind, they are
>    functions of one variable, with handler-case, they're, in effect,
>    restricted to being anonymous functions

Again, this is just a syntactic sugar difference.

> 3. handler-case can take a :no-error error-clause.
> 
> If the form(s) signal(s) a condition, then 
> 
> 4. if an applicable error-clause declines, handler-bind tries the
>    rest, handler-case does not

This is the *key* difference: in handler-bind, the registered handler
function can return. When it does so, the condition is not considered
handled and the search continues. No unwinding is performed at all.

In handler-case, a non-local exit is performed before the body of the
matching handler is executed. This means unwinding is performed and
the error is handled.

To paraphrase words once written by Kent Pitman, handler-case is a
simplified interface for programmers coming from languages whose
exception handling systems are designed for containing errors, rather
than handling them.

This is because the design of HANDLER-CASE has a significant defect:
it's impossible to use in conjunction with restarts.

In Lisp, one thing that an error handler can do is retrieve the list
of restarts. Restarts are blocks of code that are identified by
symbols, scattered throughout the dynamic context which leads up to
the point where the condition was signaled.

If you unwind the stack, then all the restarts in the dynamic context
between your HANDLER-CASE and the condition point are destroyed!

So it is impossible to write code like this:

  (defun foo ()
    (restart-case
      (error "ha!")
      (bar () :report "I know how to continue!"
        (print "restart-invoked"))))

  (handler-case
    (foo)
    (error (c)
      (invoke-restart 'bar))) ;; oops, no longer exists.


  (handler-bind
    ((error #'(lambda (c) (invoke-restart 'bar))))
    (foo)) ;; works!

> 5. handler-case returns the result of the applicable error-clause,
>    handler-bind does not return anything

HANDLER-BIND returns normally if there is no condition. If there is a
condition, there may be a non-local exit through the HANDLER-BIND
because none of its handlers match the condition. If a handler does
match the condition, then it is called; it's up to that handler to
perform a non-local exit which will yield some kind of return value,
if that is important, for instance:

   (block :foo
     (handler-bind ((error #'(lambda (c)
                               (print "caught error!") 
                               (return-from :foo 42))))
       (error "ha!")))

Of course, it's the block that is returning 42, not HANDLER-BIND,
strictly speaking.  But HANDLER-CASE achieves the value returning in
some similar way; the block is just hidden from you by the syntactic
sugar.

Try experimenting with MACROEXPAND on the HANDLER-BIND and
HANDLER-CASE forms to see how your Lisp system impelments them.

> Am I right that no. 4 is the only non-trivial difference? And that
> this feature of handler-bind could be simulated by nested
> handler-cases, as in

HANDLER-BIND cannot be simulated by nested HANDLER-CASE constructs
because the unwinding that they perform cannot be undone.

But of course HANDLER-CASE can be implemented in terms of
HANDLER-BIND. Use MACROEXPAND-1 to expand a quoted HANDLER-CASE
construct; chances are it is done that way. Here is is an expansion
from one Lisp system:

  (macroexpand-1 '(handler-case A (B () C D)))

==>

(BLOCK #:G580
 (LET (#:G581)
  (TAGBODY
   (RETURN-FROM #:G580
    (HANDLER-BIND
     ((B #'(LAMBDA (CONDITION) 
             (DECLARE (IGNORE CONDITION)) 
             (GO #:G579)))) 
     A))
   #:G579 
  (RETURN-FROM #:G580 (LET NIL C D))))) ;

Note the (GO #:G579) which performs the non-local exit before the body
of the clause is executed, and the use of a surrounding block to
implement the value-returning behavior of HANDLER-CASE.

But of course, the specific implementation above, though illustrative,
is not required.
From: Simon Andr�s
Subject: Re: handler-case vs handler-bind
Date: 
Message-ID: <vcdvfyuoigx.fsf@tarski.math.bme.hu>
Thanks a lot to all of you, and especially to Kaz for his detailed and
very clear explanation and examples. Looks like I have to learn about
restarts before I can appreciate handler-bind. But that's what I was
going to do anyway.

Andras
From: Tim Bradshaw
Subject: Re: handler-case vs handler-bind
Date: 
Message-ID: <ey3wuj8ofg1.fsf@cley.com>
* Simon Andr�s wrote:
> Thanks a lot to all of you, and especially to Kaz for his detailed and
> very clear explanation and examples. Looks like I have to learn about
> restarts before I can appreciate handler-bind. But that's what I was
> going to do anyway.

It's not just restarts, it's when the code associated with the handler
gets to run.  In HANDLER-CASE it runs *after* the stack has unwound,
while in HANDLER-BIND it runs before.  You can use HANDLER-BIND to
implement HANDLER-CASE, but you can also use it to do things like
`default error handling'. To do this, you resignal the condition you
got: if control returns, then no one else handled the condition, and
you handle it yourself, performing a suitable transfer of control.

--tim
From: Nils Goesche
Subject: Re: handler-case vs handler-bind
Date: 
Message-ID: <lyadg718b6.fsf@cartan.de>
······@math.bme.hu (Simon Andr�s) writes:

> As part of an effort to make myself more comfortable with the
> condition system, I'm trying to understand the difference between
> handler-case and handler-bind.  The following list is what I came up
> with. I wonder if it's correct and exhaustive.

> If the form(s) signal(s) a condition, then 
...
> 4. if an applicable error-clause declines, handler-bind tries the
>    rest, handler-case does not
...
> Am I right that no. 4 is the only non-trivial difference?

No.  The most important difference is that once you are in the body of
a error-clause of a HANDLER-CASE, control has already been transferred
and dynamic state has unwound.  This doesn't necessarily happen with
HANDLER-BIND, which makes HANDLER-BIND /much/ more useful.  You can
INVOKE-RESTART, for instance.  If you don't know it yet, read Kent
Pitman's paper

  http://world.std.com/~pitman/Papers/Condition-Handling-2001.html

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0
From: Lars Brinkhoff
Subject: Re: handler-case vs handler-bind
Date: 
Message-ID: <85fzpz2kxm.fsf@junk.nocrew.org>
······@math.bme.hu (Simon Andr�s) writes:
> As part of an effort to make myself more comfortable with the
> condition system, I'm trying to understand the difference between
> handler-case and handler-bind.

What a coincidence, I've been doing that too!  Here's some code I
wrote to understand conditions, handlers, and restarts.  Call f1 to
see what happens.

  ;; new condition called foo
  (define-condition foo () ())
  
  (defun f1 ()
    ;; You can't use handler-case for this.
    (handler-bind ((foo (lambda (c)
                          (declare (ignore c))
                          (print "f1 handles foo and calls f4")
                          (f4))))
      (print "f1 calls f2")
      (f2)))
  
  (defun f2 ()
    (print "f2 calls f3")
    (restart-case (f3)
      (bar ()
        (print "f2 continues")))
    (print "f2 returns 42")
    42)
  
  (defun f3 ()
    (print "f3 signals foo")
    (signal 'foo))
  
  (defun f4 ()
    (print "f4 calls the bar restart")
    (invoke-restart 'bar))

Then, to confuse things more, I wrote this to test whether I reverse
the roles of conditions and restarts.  Sure enough, it seems to work.
Start by calling g1.

  (defun g1 ()
    (restart-bind ((bar (lambda ()
                          (print "g1 handles bar and calls g4")
                          (g4))))
      (print "g1 calls g2")
      (g2)))
  
  (defun g2 ()
    (print "g2 calls g3")
    (handler-case (g3)
      (foo ()
        (print "g2 continues")))
    (print "g2 returns 42")
    42)
  
  (defun g3 ()
    (print "g3 calls the bar restart")
    (invoke-restart 'bar))
  
  (defun g4 ()
    (print "g4 signals foo")
    (signal 'foo))

-- 
Lars Brinkhoff,         Services for Unix, Linux, GCC, PDP-10, HTTP
Brinkhoff Consulting    http://www.brinkhoff.se/
From: Lars Brinkhoff
Subject: Re: handler-case vs handler-bind
Date: 
Message-ID: <8565qv2d0k.fsf@junk.nocrew.org>
Lars Brinkhoff <·········@nocrew.org> writes:
> Then, to confuse things more, I wrote this to test whether I [could]
> reverse the roles of conditions and restarts.

Only in this example, not in general, I haste to add.

-- 
Lars Brinkhoff,         Services for Unix, Linux, GCC, PDP-10, HTTP
Brinkhoff Consulting    http://www.brinkhoff.se/