From: Alan Crowe
Subject: handler-case versus handler-bind
Date: 
Message-ID: <86n08gmcgw.fsf@cawtech.freeserve.co.uk>
I'm trying to learn the CL condition system.
I particularly wanted to follow the thread on 
Newtons method. I found the condition stuff
baffling. I couldn't see were the error was
thrown from.

I'm been working through stuff but have come
unstuck at

http://www.lispworks.com/reference/HyperSpec/Body/f_abortc.htm

    ;;; Example of the MUFFLE-WARNING restart

     (defun count-down (x)
       (do ((counter x (1- counter)))
	   ((= counter 0) 'done)
	 (when (= counter 1)
	   (warn "Almost done"))
	 (format t "~&~D~%" counter)))
    =>  COUNT-DOWN
     (count-down 3)
    >>  3
    >>  2
    >>  Warning: Almost done
    >>  1
    =>  DONE
     (defun ignore-warnings-while-counting (x)
       (handler-bind ((warning #'ignore-warning))
	 (count-down x)))
    =>  IGNORE-WARNINGS-WHILE-COUNTING
     (defun ignore-warning (condition)
       (declare (ignore condition))
       (muffle-warning))
    =>  IGNORE-WARNING
     (ignore-warnings-while-counting 3)
    >>  3
    >>  2
    >>  1
    =>  DONE

I cut and paste this into CMUCL and it works. So I
try my own variation to check I have understood.

(defun skip-warnings-while-counting(x)
  (handler-case (count-down x)
    (warning ()
      (muffle-warning))))

(skip-warnings-while-counting 5)

5
4
3
2
Restart NIL is not active.
Error flushed ...

So there is some kind of subtle difference between
handler-case and handler-bind, but it has got me stumped.
Help!

Alan Crowe
Edinburgh
Scotland

From: Joe Marshall
Subject: Re: handler-case versus handler-bind
Date: 
Message-ID: <7jzk9hyh.fsf@ccs.neu.edu>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

> So there is some kind of subtle difference between
> handler-case and handler-bind, but it has got me stumped.

HANDLER-CASE is similar to the TRY/CATCH forms that have become
popular in other languages --- a signal is raised, the stack is
unwound and processing continues at the catcher.  This is a reasonable
way of handling a lot of errors and is usually sufficient.

HANDLER-BIND is what you use when you need absolute control over what
happens when a signal is raised.  The handler in this case is
different from the handler above (which is one source of confusion).
The handler here runs in the context of the error *before* any throw
happens.  It can decide where to throw to or whether or not to throw
at all.

As it turns out, it is easy to write HANDLER-CASE in terms of
HANDLER-BIND --- you just wrap the handler-case handler in some code
that throws and then invokes the handler-case handler.
From: Steven E. Harris
Subject: Re: handler-case versus handler-bind
Date: 
Message-ID: <q67ptdbj37o.fsf@L75001820.us.ray.com>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

> I'm trying to learn the CL condition system.  I particularly wanted
> to follow the thread on Newtons method. I found the condition stuff
> baffling. I couldn't see were the error was thrown from.

Since posting the first Newton's method question a couple of days ago,
I too have been struggling to fully understand that restart-related
code -- and I wrote it. It was my first cut at using restarts. I've
been too busy trying to understand the floating point problems to come
up for air and ask for clarification about restarts, conditions, and
handlers.

My questions lie more with how to set up restarts that only apply to a
particular condition type. There's a note in the HyperSpec entry for
restart-case� that reads

  If the restartable-form is a list whose car is any of the symbols
  signal, error, cerror, or warn (or is a macro form which
  macroexpands into such a list), then with-condition-restarts is used
  implicitly to associate the indicated restarts with the condition to
  be signaled.

I read that "associate the indicated restarts with the condition" to
mean that these restarts would only be available for the condition
being signaled right there by signal, error, cerror, or warn. But, at
least on CLISP here, it seems that the same restarts are always
available for any errors raised within restartable-form, unless I use
the :test option to check the signaled condition type.

Restated, I was looking for some way to express something like, "Run
this form, and if this type of condition arises anywhere within the
form, add this restart as a candidate." In the Newton's method
example, it would be nice to have a restart that, in the face of a
signaled convergence-failure, could optionally continue the loop where
it left off with a new max-iterations specified. But that restart
should not be available for errors other than convergence-failure. It
wouldn't make sense to offer to continue a loop because, say, a
floating-point underflow error occurred somewhere within it.

I couldn't figure out how to do that -- to get the final computed
value, and re-run the loop supplying the final value as the initial
value and a new number of iterations.


Footnotes: 
� http://www.lispworks.com/reference/HyperSpec/Body/m_rst_ca.htm

-- 
Steven E. Harris        :: ········@raytheon.com
Raytheon                :: http://www.raytheon.com
From: Steven E. Harris
Subject: Re: handler-case versus handler-bind
Date: 
Message-ID: <q67k73jj1dl.fsf@L75001820.us.ray.com>
"Steven E. Harris" <········@raytheon.com> writes:

> I couldn't figure out how to do that -- to get the final computed
> value, and re-run the loop supplying the final value as the initial
> value and a new number of iterations.

Following up to myself, I did figure out one way to do this, but it's
not pretty. I included the condition type used in the Newton's method
example. Here, we increment a value by the current iteration count
until either the value exceeds 300 or we hit our maximum iteration
count. At that point, restarts permit acceptance, substitution, or
continuation.


(define-condition convergence-failure (error)
  ((value :initarg :value :reader convergence-failure-value)
   (iterations :initarg :iterations :reader convergence-failure-iterations))
  (:report (lambda (condition stream)
             (format stream "Newton's method failed to converge in ~A iterations.~%Final value: ~A."
                     (convergence-failure-iterations condition)
                     (convergence-failure-value condition)))))


(let ((max-iterations 10))
  (loop for i
    with val = 1
    thereis (if (> val 300)
                val
                (when (= i max-iterations)
                  (restart-case
                   (error 'convergence-failure :value val :iterations max-iterations)
                   (use-final-value ()
                                    :report (lambda (stream)
                                              (format stream "Use final computed value ~A." val))
                                    val)
                   (use-value (other-val)
                              :report (lambda (stream)
                                        (format stream "Input another value instead of ~A." val))
                              :interactive (lambda ()
                                             (format *query-io* "Use instead of ~A: " val)
                                             (multiple-value-list (eval (read))))
                              other-val)
                   (continue-iterating (iterations)
                                       :report (lambda (stream)
                                                 (format stream "Continue iteration with a new bound." ))
                                       :interactive (lambda ()
                                                      (format *query-io* "Continue for additional iterations: ")
                                                      (multiple-value-list (eval (read))))
                                       (incf max-iterations iterations)
                                       nil))))
    do (incf val i)))

-- 
Steven E. Harris        :: ········@raytheon.com
Raytheon                :: http://www.raytheon.com
From: Jon S. Anthony
Subject: Re: handler-case versus handler-bind
Date: 
Message-ID: <m3ektsm0q7.fsf@rigel.goldenthreadtech.com>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:


Presumably you have already looked at

http://www.lispworks.com/reference/HyperSpec/Body/m_hand_1.htm

In particular take a look at the notes.

> (handler-bind ((warning #'ignore-warning))
>   (count-down x))
> 
> (handler-case (count-down x)
>   (warning ()
>     (muffle-warning)))

And then macroexpand-1 your handler-case in your system.


/Jon
From: Tim Bradshaw
Subject: Re: handler-case versus handler-bind
Date: 
Message-ID: <ey3d69ccf5x.fsf@cley.com>
* Alan Crowe wrote:

> So there is some kind of subtle difference between
> handler-case and handler-bind, but it has got me stumped.
> Help!

The important difference is that in HANDLER-CASE, the condition has
been handled when your code runs while in HANDLER-BIND your code gets
to decide whether it should handle it or not (by either retiurning
normally, which declines to handle the condition, or doing a
non0-local transfer of control, which handles it).  In particular, for
HANDLER-CASE the stack has been unwound at the point when your code
runs, so any other handlers which might have been on the stack are no
longer active.

A very naive expansion is something like this:

(handler-case
  <form>
 (foo (c)
   (format t "~&Handled ~A~%" c)))

-->

(block done
  (let ((c nil))
    (tagbody
      (handler-bind
        ((foo #'(lambda (x) (setf c x) (go handle-foo))))
        (return-from done <form>))
      handle-foo
      (return-from done (format t "~&Handled ~A~%" c)))))

This is obviously naive because of the lack of gensyms and also it may
well be just wrong.  The point here is that the code in the
HANDLER-CASE runs *after* the condition has been handled, and the
stack unwound and so on: when the HANDLER-CASE code runs it's too late
to decide whether or not to handle the condition, as that decision has
already been made.

--tim

        
      
    
From: Alan Crowe
Subject: Re: handler-case versus handler-bind
Date: 
Message-ID: <86k73hmwxf.fsf@cawtech.freeserve.co.uk>
Tim Bradshaw offered the following illustrative macro
expansion.

(handler-case
  <form>
 (foo (c)
   (format t "~&Handled ~A~%" c)))

-->

(block done
  (let ((c nil))
    (tagbody
      (handler-bind
        ((foo #'(lambda (x) (setf c x) (go handle-foo))))
        (return-from done <form>))
      handle-foo
      (return-from done (format t "~&Handled ~A~%" c)))))

This is similar to what is in the Hyperspec. What
intrigued/confused me is that handler-case unwinds the
stack, and handler-bind doesn't, yet handler-case is a macro
on top of handler-bind.

So I'm looking to see a magically-unwind-stack command in the
macro expansion. I think it is the innocuous looking (go
handle-foo). My reasons are 

a) the spec makes a big deal out of non-local exits. If the
   handler just returns, it is said to have declined the
   condition and the condition system looks at the next
   handler up the stack

b) http://www.lispworks.com/reference/HyperSpec/Body/05_b.htm 

I've now written a couple of test cases:

(defun signal-error()
  (restart-case
   (error "Oh, shit!")
   (try-again() "No worries, mate.")))

(defun explore-go(invoke)
  (tagbody
   (handler-bind((error #'(lambda(c)(declare (ignore c))
			    (format t "first attempt at finding restart: ~A~%"
				    (find-restart 'try-again))
			    (if invoke (invoke-restart 'try-again))
			    (go unwind-stack))))
		(format t "(signal-error) returns: ~A~%" (signal-error)))
   (format t "Handle bound~%")
   (go end)
   unwind-stack
   (format t "Second attempt at finding restart: ~A~%"
	   (find-restart 'try-again))
   end))

* (explore-go t)
first attempt at finding restart: TRY-AGAIN
(signal-error) returns: No worries, mate.
Handle bound
NIL
* (explore-go nil)
first attempt at finding restart: TRY-AGAIN
Second attempt at finding restart: NIL
NIL

Which seems to prove the point, it is the (go ...) that
unwinds the stack. I find the way in which the various CL
features work together endlessly fascinating. When Steele
wrote

    The lexical scoping of the go targets named by tags is
    fully general and has consequences that may be
    surprising ... Depending on the situation, a go in
    COMMON LISP does not necessarily correspond to a simple
    machine "jump" instruction!

I thought "Cool, but so what?" Now I see that if (go ...)
does the right thing, then one doesn't need an extra "unwind
the stack" primitive in the condition system.

Many thanks for all the encouragement to pursue the
difference between handler-bind and handler-case.

Alan Crowe
Edinburgh
Scotland
From: Tim Bradshaw
Subject: Re: handler-case versus handler-bind
Date: 
Message-ID: <ey3wu7hbhzf.fsf@cley.com>
* Alan Crowe wrote:
> I thought "Cool, but so what?" Now I see that if (go ...)
> does the right thing, then one doesn't need an extra "unwind
> the stack" primitive in the condition system.

I think that, even more than this, one doesn't need to introduce a
whole notion of stacks and unwinding them and so on.  If GO just goes
to a tag within its TAGBOGY, making sure that the state when it gets
there is `right' - so any dynamic `bindings' (variables or other
things) which might have happened in the interim have un-happened,
then you're OK.  A simple example is something like:

(tagbody
  (let ((*print-base* 2))
    (print 2)
    (go outer))
  outer
  (print 2))

Then of course the magic is that GO tags have lexical scope (but
dynamic extent, because we're CL not scheme), so you can do tricks
like:

  (let ((r nil))
    (tagbody
      (setf r (big-complicated-function #'(lambda (e)
                                            (setf r e)
                                            (go done))))
      done
      (identity r)))

And now the function passed to BIG-COMPLICATED-FUNCTION is sort of an
`escaper', which lets you give up and return a value.

This particular trick is better done with blocks:

  (block done
    (return-from done (big-complicated-function #'(lambda (e)
                                                    (return-from done e)))))

But this is really the same idea.
From: Frode Vatvedt Fjeld
Subject: Re: handler-case versus handler-bind
Date: 
Message-ID: <2hk73kb2v0.fsf@vserver.cs.uit.no>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

> [..] So there is some kind of subtle difference between handler-case
> and handler-bind, but it has got me stumped.  Help!

When an exceptional situation occurs, control is transfered to some
function based on the current handler-bindings. In other words, an
exception (i.e. "signalling a condition") is essentially a
function-call to some unknown function (the "handler") that someone
else decided is appropriate for dealing with the situation specified
by the condition object that is being signalled. Handler-bind is how
you, in the role of "someone else", make such decisions.

A common way to handle unforeseen situations is to unwind the stack
and transfer control to some outer scope of the
computation. Handler-case provides convenient syntax for doing this.


For example, the debugger is typically installed with (the equivalent
of) handler-bind, as the handler of last resort. The debugger needs to
run in the context of the exceptional situation. It would be much less
useful if invoked only after the stack was unwound and control back at
the top-level.

-- 
Frode Vatvedt Fjeld
From: Wolfhard Buß
Subject: Re: handler-case versus handler-bind
Date: 
Message-ID: <m3oeswgjsk.fsf@buss-14250.user.cis.dfn.de>
* Alan Crowe writes:

> I'm trying to learn the CL condition system.
> I particularly wanted to follow the thread on 
> Newtons method. I found the condition stuff
> baffling. I couldn't see were the error was
> thrown from.
>
> I'm been working through stuff but have come
> unstuck at
>
> http://www.lispworks.com/reference/HyperSpec/Body/f_abortc.htm
>
>     ;;; Example of the MUFFLE-WARNING restart
>
>      (defun count-down (x)
>        (do ((counter x (1- counter)))
> 	   ((= counter 0) 'done)
> 	 (when (= counter 1)
> 	   (warn "Almost done"))
> 	 (format t "~&~D~%" counter)))
:
> (defun skip-warnings-while-counting(x)
>   (handler-case (count-down x)
>     (warning ()
>       (muffle-warning))))
>
> (skip-warnings-while-counting 5)
>
> 5
> 4
> 3
> 2
> Restart NIL is not active.
> Error flushed ...
>
> So there is some kind of subtle difference between
> handler-case and handler-bind, but it has got me stumped.

count-down and the muffle-warning restart established by warn are
already pass� when the restart function muffle-warning tries to invoke
the muffle-warning restart.

-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)