Re: (warn) isn't doing what I expect it to



Nathan Baum <nathan_baum@xxxxxxxxxxxxxx> writes:

> Nathan Baum wrote:
> > I'm expecting
> > (handler-case
> > (warn "foo")
> > (warning (c) (muffle-warning c)))
> > to produce no output, successfully. Instead it produces
> > *** - INVOKE-RESTART: No restart named MUFFLE-WARNING is visible.
> > CLHS says WARN establishes a MUFFLE-WARNING restart. What am I doing
> > wrong?
>
> So HANDLER-CASE unwinds the dynamic environments before executing its
> forms. Most unexpected.

Right. And it's the normal semantics for Java and C++.
That is to say, it is often useless in doing serious error handling.
Both of those languages lack the ability to handle the error in its
original context, which is the time when interesting restarts are
possible. In fact, they have no restart facility at all. Just a
catch-like facility. Because once you've thrown out of the error, that
nuance of how to proceed is far less relevant.

> It works if I use HANDLER-BIND.
>
> (handler-bind
> ((warning #'(lambda (c) (muffle-warning c))))
> (warn "foo"))
>
> I think that's a bit ugly, though. Is there a common idiom for what I
> want to do, or should I go ahead and roll my own macro?

If all you're going to write is that, use
(handler-bind ((warning #'muffle-warning))
(warn "foo"))
Some people prefer to protect themselves from non-conforming implementations
and might write:
(handler-bind ((warning #'(lambda (c)
(let ((r (find-restart 'muffle-warning c)))
(when r (invoke-restart r))))))
(warn "foo"))
Though there's no reason you can't write
(defun muffle-warnings-if-possible (warning)
(let ((restart (find-restart 'muffle-warning warning)))
(when restart (invoke-restart appropriate-restart))))
and then something like
(defmacro muffling-warnings (&body forms)
`(handler-bind ((warning #'muffle-warnings-if-possible))
,@forms))
so that you can just do
(muffling-warnings
(warn "foo"))
.