Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

handler-bind

30 views
Skip to first unread message

Keke Abe

unread,
May 11, 2001, 5:39:24 AM5/11/01
to
I'm wondering whether the second handler of the following
handler-bind form should be called or not.

(catch 'abort
(handler-bind ((error #'(lambda (c)
(declare (ignore c))
(princ "Handler #1")))
(error #'(lambda (c)
(declare (ignore c))
(princ "Handler #2")
(throw 'abort nil))))
(error "testing handler-bind")))


The HyperSpec [9.1.4 Signaling and Handling Conditions] says:

[...]
Once a handler in a handler binding form (such as
handler-bind or handler-case) has been selected, all handlers
in that form become inactive for the remainder of the
signaling process. While the selected handler runs, no other
handler established by that form is active. That is, if the
handler declines, no other handler established by that form
will be considered for possible invocation.

It looks like suggesting that the second handler of the above won't
be invoked. However, the following [again from HyperSpec on
HANDLER-BIND]:

[...]
If more than one handler binding is supplied, the handler
bindings are searched sequentially from top to bottom in
search of a match (by visual analogy with typecase). If an
appropriate type is found, the associated handler is run in a
dynamic environment where none of these handler bindings are
visible (to avoid recursive errors). If the handler declines,
the search continues for another handler.

sounds like indicating that the second handler should be called.
Where have I lost?

Thanks for your help.
Takehiko Abe

--
"If this were a dictatorship, it'd be a heck of a lot easier,
just so long as I'm the dictator."
- George W Bush

Kent M Pitman

unread,
May 11, 2001, 5:58:14 AM5/11/01
to
ke...@mac.com (Keke Abe) writes:

I think it means the search continues outward for other,
dynamically-enclosing clusters of handler-bindings.

The intent of allowing HANDLER-BIND more than one binding is to allow you
to provide specific handlers for a specific circumstance, but the handler
bindings in any given HANDLER-BIND are intended to deal with a unitary
understanding of a situation.

Using nested HANDLER-BINDs will do what looks like the right thing for you.

Keke Abe

unread,
May 11, 2001, 9:30:48 AM5/11/01
to
In article <sfwheys...@world.std.com>,
Kent M Pitman wrote:

> I think it means the search continues outward for other,
> dynamically-enclosing clusters of handler-bindings.
>
> The intent of allowing HANDLER-BIND more than one binding is to allow you
> to provide specific handlers for a specific circumstance, but the handler
> bindings in any given HANDLER-BIND are intended to deal with a unitary
> understanding of a situation.
>

Thank you. I came to this question last October and thought that it might
be a bug of MCL (the implementation I use). I even posted the same question
to the MCL mailing list but didn't get much response then. I should have
asked this earlier here in comp.lang.lisp so that I could get the answer
from you.

Now that I've got a definitive answer [I am fully aware that you are not
the HyperSpec nor the ANSI CL Spec], I think I should post to the MCL
mailing again. Could I quote you in it?

regards,
Takehiko Abe
--
[silly sig deleted]

Kent M Pitman

unread,
May 12, 2001, 9:51:30 AM5/12/01
to
ke...@mac.com (Keke Abe) writes:

Sorry to take so long to get back to you on this; I got delayed by some
research on the topic I tried to do.

You can quote me as having said what I said, but let me add that the one
thing I *really* wanted to do was to go back to the sample implementation
I had distributed. I've been poking around in my online files and fear it's
also among the things that's presently offline (in backups). I think I've
distributed copies to others around the net, though, so if anyone has a copy
of the Revision 18 sample implementation and they could send me a pointer,
that'd be handy. I'd consider that implementation, because it was
incorporated by a number of vendors, to be more definitive.

The truth is, though, that any legitimate interpretation of the
wording is valid and conforming. It is not the place of any one
person or organization to dictate what is right.

I looked back at the original proposal to ANSI (which was incorporated
into the draft standard and subsequently modified in various ways, but
not, I believe, on this point) and it has pretty much the same wording.

If more than one binding is specified, the bindings are searched

sequentially from top to bottom in search of a match (by visual analogy

with TYPECASE). If an appropriate type is found, the associated handler
is run in a context where none of the BINDINGS are visible (to avoid
recursive errors). For example, in the case of:
(HANDLER-BIND ((UNBOUND-VARIABLE #'(LAMBDA ...))
(ERROR #'(LAMBDA ...)))
...)
if an unbound variable error is signalled in the body (and not handled
by an intervening handler), the first function will be called. If any
other kind of error is signalled, the second function will be called.
In either case, neither handler will be active while executing the code
in the associated function.

Btw, LispWorks 4.1.20 disagrees with me, at least in implementation, not
sure about intent. It does:

(handler-bind ((error #'(lambda (c) (break "Bar: ~A" c))))
(handler-bind ((error #'(lambda (c) nil))
(error #'(lambda (c) (break "Foo: ~A" c))))
(error "Testing...")))

Foo: Testing...

where I would have expected to break with "Bar: Testing...".

Both interpretations seem "reasonable" and I don't know what to say is
right. But my impression is that it's more debuggable if you think of
each handler-bind as a typecase (which would mean only one item gets done)
and the search as a process of trying each of those typecases. But
I can imagine someone thinking otherwise.

The one thing that leans the argument just a little bit in favor of the
"MCL" interpretation is the remark that the handlers available in the
selected clause don't see the other handlers in the other clauses.
Normally, there is a "firewall" built that keeps the "unwound" things from
being seen but leaves the "wound" things visible as handlers are tried.
Since the sibling clauses are not visible, that gives the strongest claim
to the idea that they should also be treated as "already unwound" and so
not searched if search resumes. This is an obscure point that might have
gone past some implementors, but I would consider it to be "necessary
consistency". The only problem is that others probably wouldn't, and my
opinion's no more valuable than anyone else's, even if I did write that part
of the spec and the sample implementation. Once we voted on the standard,
only the actual words of the standard matter, and the rest of this is just
the moral equivalent of the Jerry Springer show, adapted for a parenthetically inclined audience.

So my feeling is now firmly for that MCL position is the best one for
internal consistency of the language, but that both the MCL and LW positions
are at least superficially defensible.

Pierre R. Mai

unread,
May 12, 2001, 10:56:34 AM5/12/01
to

Both ACL and CMU CL seem to agree with LispWorks on that point, both
first breaking into the Foo: Testing break-loop, instead of proceeding
directly into the Bar: Testing break-loop...

CLISP seems to agree with the MCL interpretation.

FWIW the CMU CL conditions implementation seems to be based on your
prototypical implementation, though it is really unclear which version
of that implementation that was, and whether later changes have any
bearing on that aspect. From the source:

;;;
;;; This is a condition system for CMU Common Lisp.
;;; It was originally taken from some prototyping code written by KMP@Symbolics
;;; and massaged for our uses.
;;;

> So my feeling is now firmly for that MCL position is the best one for
> internal consistency of the language, but that both the MCL and LW positions
> are at least superficially defensible.

Indeed I would have expected the MCL position to be more wide-spread
than it is.

Regs, Pierre.

--
Pierre R. Mai <pm...@acm.org> http://www.pmsf.de/pmai/
The most likely way for the world to be destroyed, most experts agree,
is by accident. That's where we come in; we're computer professionals.
We cause accidents. -- Nathaniel Borenstein

Kent M Pitman

unread,
May 12, 2001, 2:07:59 PM5/12/01
to
"Pierre R. Mai" <pm...@acm.org> writes:

> Kent M Pitman <pit...@world.std.com> writes:

> [...]

> Indeed I would have expected the MCL position to be more wide-spread
> than it is.

I'm sure if we dig far enough we'll find that the divergence is due to
me forgetting the original intent and sending some bug report arguing
it should be changed, and then them believing me more than they should
have.
--Kent (only half-joking -- sigh)


Keke Abe

unread,
May 13, 2001, 9:24:04 AM5/13/01
to
In article <sfwzoci...@world.std.com>, Kent M Pitman <pit...@world.std.com> wrote:

> [...]


> The truth is, though, that any legitimate interpretation of the
> wording is valid and conforming. It is not the place of any one
> person or organization to dictate what is right.

I suppose this flexibility is good. Dogmatic interpretation of the
script --literalism leads to all the evil. Yet I think knowing the
original intent [as recalled or recorded] is valuable.

> I looked back at the original proposal to ANSI (which was incorporated
> into the draft standard and subsequently modified in various ways, but
> not, I believe, on this point) and it has pretty much the same wording.
>
> If more than one binding is specified, the bindings are searched
> sequentially from top to bottom in search of a match (by visual analogy
> with TYPECASE). If an appropriate type is found, the associated handler
> is run in a context where none of the BINDINGS are visible (to avoid
> recursive errors). For example, in the case of:
> (HANDLER-BIND ((UNBOUND-VARIABLE #'(LAMBDA ...))
> (ERROR #'(LAMBDA ...)))
> ...)
> if an unbound variable error is signalled in the body (and not handled
> by an intervening handler), the first function will be called. If any
> other kind of error is signalled, the second function will be called.
> In either case, neither handler will be active while executing the code
> in the associated function.

I looked into the TeX source of ANSI Draft, and the part of the HANDLER-BIND
dictionary contains the following comment:

%!!! Barmar: The next two paragraphs belong in description of signaling,
% not handling. [I agree. -kmp]
If more than one \param{handler} \term{binding} is supplied, [...]

I'm not sure what the comment means. Also, for 9.1.4 Signaling and Handling
Conditions, there is:

%!!! Barrett: This doesn't match my reading of CSv18, p12.
% I believe contradicts p21,p22 of that document. It also differs from
% previous paragraph (w/ item 2) and first paragraph under "signaling".
Once a handler in a handler binding \term{form} (such as
\macref{handler-bind} or \macref{handler-case}) has been selected, all
handlers in that \term{form} become inactive for

the remainder of the signaling process.

%--------------------------------------
While the selected \term{handler} runs, no other \term{handler} established
by that \term{form} is active. That is, if the \term{handler} declines,
no other handler established by that \term{form} will be considered for
possible invocation.
%-------------------------------------------------------------------------

The "previous paragraph":

2. Let h1 and h2 be two applicable active handlers established by the same
form. Then h1 is more recent than h2 if h1 was defined to the left of h2 in
the form that established them.


The "first paragraph under \"signaling\"":

9.1.4.1 Signaling

When a condition is signaled, the most recent applicable active handler is
invoked. Sometimes a handler will decline by simply returning without a
transfer of control. In such cases, the next most recent applicable active
handler is invoked.

Again, I'm not sure what contradicts what. I don't know what CSv18 is.
Maybe that's the sample implementation you're looking for?

[btw, I didn't know that the TeX source of ANSI drafts contains all those
very interesting comments until Kim Barret mentioned to it in MCL mailing
a while back. I found them valuable reading as a supplement to the
HyperSpec.... Just for those who don't know yet that they're available.
btw2, I regarded the HyperSpec as a reference material at first but then
found it make a very good reading material and imo its organization an
improvement from that of CLtL2. I want a handbook version.]


> Btw, LispWorks 4.1.20 disagrees with me, at least in implementation, not
> sure about intent. It does:
>
> (handler-bind ((error #'(lambda (c) (break "Bar: ~A" c))))
> (handler-bind ((error #'(lambda (c) nil))
> (error #'(lambda (c) (break "Foo: ~A" c))))
> (error "Testing...")))
>
> Foo: Testing...
>
> where I would have expected to break with "Bar: Testing...".
>
> Both interpretations seem "reasonable" and I don't know what to say is
> right. But my impression is that it's more debuggable if you think of
> each handler-bind as a typecase (which would mean only one item gets done)
> and the search as a process of trying each of those typecases. But
> I can imagine someone thinking otherwise.

I came to the question originally while I was reading the HyperSpec and
learning the Condition system [still learning] and trying some possible
use of its functions. I thought I could make one handler a default method
for a set of conditions and do some common handling there:

(define-condition condition-a () ...)
(define-condition condition-a-1 (condition-a) ...)
...
(handler-bind ((condition-a #'(lambda (c) .....))
(condition-a-1 #'(lambda (c) ...))
(condition-a-2 #'(lambda (c) ...)))
....)

So I was learning/experimenting, and this isn't what I _really_ need.
I'm not sure this makes debugging tasks harder. I must admit that I
am a kind of person who can't grasp what makes a bad coding style
til I am hit hard.

>
> The one thing that leans the argument just a little bit in favor of the
> "MCL" interpretation is the remark that the handlers available in the
> selected clause don't see the other handlers in the other clauses.
> Normally, there is a "firewall" built that keeps the "unwound" things from
> being seen but leaves the "wound" things visible as handlers are tried.
> Since the sibling clauses are not visible, that gives the strongest claim
> to the idea that they should also be treated as "already unwound" and so
> not searched if search resumes. This is an obscure point that might have
> gone past some implementors, but I would consider it to be "necessary
> consistency". The only problem is that others probably wouldn't, and my
> opinion's no more valuable than anyone else's, even if I did write that part
> of the spec and the sample implementation. Once we voted on the standard,
> only the actual words of the standard matter, and the rest of this is just
> the moral equivalent of the Jerry Springer show, adapted for a parenthetically
> inclined audience.

I don't know what the Jerry Springer show is or how good it is, but I
think the information you provided here for us is very valuable. Thank
you.

regards,
Takehiko Abe

Kent M Pitman

unread,
May 13, 2001, 11:27:41 AM5/13/01
to
ke...@mac.com (Keke Abe) writes:

> Again, I'm not sure what contradicts what. I don't know what CSv18 is.
> Maybe that's the sample implementation you're looking for?

No, but there were two joined documents.

Condition System, Revision 18
[ http://world.std.com/~pitman/Papers/Revision-18.txt

and an accompanying sample implementation that purported to implement
this particular revision.

> [btw, I didn't know that the TeX source of ANSI drafts contains all those
> very interesting comments until Kim Barret mentioned to it in MCL mailing
> a while back. I found them valuable reading as a supplement to the
> HyperSpec.... Just for those who don't know yet that they're available.
> btw2, I regarded the HyperSpec as a reference material at first but then
> found it make a very good reading material and imo its organization an
> improvement from that of CLtL2. I want a handbook version.]

Well, the problem is that the TeX source contains contradictory and
out-of-date comment information that would be confusing, so I haven't
in general cited it. But certainly we do from time to time go back to it
to see if it offers "clues".

CLTL2 is different in other than just organization. It contains
factually different information, not authorized for release by the
committee. I suppose in that sense, so does the TeX source of the
spec. Into the TeX source of the ANSI CL document, I just dumped lots
of stuff into comments when I didn't have any other place for it, so
it's got a lot of archeological interest, but perhaps less formal
interest. But back to CLTL to make another point that I haven't had a
chance to make in a while: CLTL1 was a committee product, approved and
reviewed by a committee. CLTL2 was a private effort by Steele, not
authorized by the committee, that took a snapshot of work in progress,
some of which we backed out of before the end. Further CLTL2 was
presented in a style that emphasized diffs, more than truth, and so
made it very hard to read because it's always saying "x is true. no
wait, it isn't any more. we changed that." To some degree, the TeX
comments occasionally share this sense, too.

And the TeX sourcs are a pretty tedious read.

[Also, btw, just to be 100% literal about this, you don't have the TeX source
of ANSI CL itself. What you have differs only in cosmetic ways, and in no
technical way, but for copyright reasons there is a minor difference. Not
to mention a difference in about 200 pages (1150 pages in ANSI CL instead
of 1350 in the draft you can make from the publicly available sources) that
I got by "book design" (font choice and squeezing out vertical whitespace)
for final publication!]

> > ... Once we voted on the standard, only the actual words of the


> > standard matter, and the rest of this is just the moral equivalent
> > of the Jerry Springer show, adapted for a parenthetically inclined
> > audience.
>
> I don't know what the Jerry Springer show is or how good it is,

(It's extraordinarily popular with the mainstream public of the US,
consisting mostly of invited guests on outlandish topics saying rude
things to each other until they get mad enough that they try to beat
each other up and have to be stopped by big burly guys hired by the
show to keep the guests from killing each other.)

> but I think the information you provided here for us is very valuable.
> Thank you.

Happy to help. I'm sure I'll find the sample implementation at some point,
and at that point I'll post the additional clue it will provide.

Erik Naggum

unread,
May 13, 2001, 12:19:04 PM5/13/01
to
* Kent M Pitman

> Btw, LispWorks 4.1.20 disagrees with me, at least in implementation, not
> sure about intent. It does:
>
> (handler-bind ((error #'(lambda (c) (break "Bar: ~A" c))))
> (handler-bind ((error #'(lambda (c) nil))
> (error #'(lambda (c) (break "Foo: ~A" c))))
> (error "Testing...")))
>
> Foo: Testing...
>
> where I would have expected to break with "Bar: Testing...".

* "Pierre R. Mai" <pm...@acm.org>


> Both ACL and CMU CL seem to agree with LispWorks on that point, both
> first breaking into the Foo: Testing break-loop, instead of proceeding
> directly into the Bar: Testing break-loop...

I remain uncertain what we are demonstrating here, but for what it might
be worth, Allegro CL 6.0 breaks with "Bar: More Testing..." when running
this snippet of code:

(handler-bind ((error #'(lambda (c) (break "Bar: ~A" c))))

(handler-bind ((error #'(lambda (c) (error "More ~A" c)))


(error #'(lambda (c) (break "Foo: ~A" c))))
(error "Testing...")))

while breaking with "Foo: Testing..." in the example quoted above, which
does indicate that the next handler is not visible while in the handler,
but somehow reinstated when searching for an applicable handler, like
cond instead of like typecase.

#:Erik
--
Travel is a meat thing.

0 new messages