From: Vladimir Zolotykh
Subject: handler-bind lookup procedure
Date: 
Message-ID: <3CB59107.13A96E06@eurocom.od.ua>
Let me quote HyperSpec

'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.'

Seemed to me this concerns one handler-bind form. What should take place when
I have several of them nested? For example:

(handler-bind ((specific-condition-2 #'(lambda (c) (print "specific"))))
  (handler-bind ((general-condition-2 #'(lambda (c) (print "general"))))
    (signal 'specific-condition-2)))

-- 
Vladimir Zolotykh

From: Barry Margolin
Subject: Re: handler-bind lookup procedure
Date: 
Message-ID: <qhht8.8$EE6.271@paloalto-snr2.gtei.net>
In article <·················@eurocom.od.ua>,
Vladimir Zolotykh  <······@eurocom.od.ua> wrote:
>Let me quote HyperSpec
>
>'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.'
>
>Seemed to me this concerns one handler-bind form. What should take place when
>I have several of them nested? For example:

The most recently established handler that matches the condition will be
invoked.

>(handler-bind ((specific-condition-2 #'(lambda (c) (print "specific"))))
>  (handler-bind ((general-condition-2 #'(lambda (c) (print "general"))))
>    (signal 'specific-condition-2)))

This will print "general".

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Kent M Pitman
Subject: Re: handler-bind lookup procedure
Date: 
Message-ID: <sfwn0wa6yob.fsf@shell01.TheWorld.com>
Barry Margolin <······@genuity.net> writes:

> In article <·················@eurocom.od.ua>,
> Vladimir Zolotykh  <······@eurocom.od.ua> wrote:
> >Let me quote HyperSpec
> >
> >'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.'
> >
> >Seemed to me this concerns one handler-bind form. What should take place when
> >I have several of them nested? For example:
> 
> The most recently established handler that matches the condition will be
> invoked.
> 
> >(handler-bind ((specific-condition-2 #'(lambda (c) (print "specific"))))
> >  (handler-bind ((general-condition-2 #'(lambda (c) (print "general"))))
> >    (signal 'specific-condition-2)))
> 
> This will print "general".

I agree with Barry (assuming as he does that a specific-condition-2 is also
of type general-condition-2.  

However, I'm curious: what did you expect and why?  Do you think the
behavior Barry suggests is wrong, and if so, why?
From: Vladimir Zolotykh
Subject: Re: handler-bind lookup procedure
Date: 
Message-ID: <3CB5BC31.6BEB0FDE@eurocom.od.ua>
Kent M Pitman wrote:
> 
> Barry Margolin <······@genuity.net> writes:
> 
> > In article <·················@eurocom.od.ua>,
> > Vladimir Zolotykh  <······@eurocom.od.ua> wrote:
> > >Let me quote HyperSpec
> > >
> > >'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.'
> > >
> > >Seemed to me this concerns one handler-bind form. What should take place when
> > >I have several of them nested? For example:
> >
> > The most recently established handler that matches the condition will be
> > invoked.
> >
> > >(handler-bind ((specific-condition-2 #'(lambda (c) (print "specific"))))
> > >  (handler-bind ((general-condition-2 #'(lambda (c) (print "general"))))
> > >    (signal 'specific-condition-2)))
> >
> > This will print "general".
> 
> I agree with Barry (assuming as he does that a specific-condition-2 is also
> of type general-condition-2.

Sorry for forgetting that, of course

  (define-condition general-condition-2 () ())
  (define-condition specific-condition-2 (general-condition-2) ())

> 
> However, I'm curious: what did you expect and why?  Do you think the
> behavior Barry suggests is wrong, and if so, why?

Knowing CLOS a little I might guessed the more specific handler could be 
considered first. This is not. Reading HyperSpec I had supposed the visual
order governs all. This is also not. The nearest (dynamically) handler take
precedence over most specific and in one handler-bind visual order determines
all (among applicable handlers of course). I just had wanted to make sure
I understand things right.

-- 
Vladimir Zolotykh
From: Kent M Pitman
Subject: Re: handler-bind lookup procedure
Date: 
Message-ID: <sfwhemi87ox.fsf@shell01.TheWorld.com>
Vladimir Zolotykh <······@eurocom.od.ua> writes:

> Knowing CLOS a little I might guessed the more specific handler could be 
> considered first. This is not. Reading HyperSpec I had supposed the visual
> order governs all. This is also not. The nearest (dynamically) handler take
> precedence over most specific and in one handler-bind visual order determines
> all (among applicable handlers of course). I just had wanted to make sure
> I understand things right.

It is important to understand that this is a dynamic issue that intentionally
involves search.

Consider what would happen if you wrote:

 (defun reciprocal-or-nil (x) (ignore-errors (/ 1 x)))

There would be no way you could, in a modular way, prove the correctness
of this function if some containing routine could do:

 (defun one (seed)
   (handler-case (let ((recip (reciprocal-or-nil seed)))
                   (if recip
                       (* recip seed)
                       ;; otherwise,
                       ;;  if we couldn't find reciprocal,
                       ;;  just return a symbolic result
                       'one))  
     (arithmetic-error 'unknown)))

 (one 3)   => 1
 (one 3.0) => 1.0
 (one nil) => ONE
 (one 0)   => ONE

But if the "more specific" function could trap something on an inner
computation that was handled within that computation, you couldn't test
the inner computation in isolation, and you'd get

 (one 0) => UNKNOWN

even though 

 (reciprocal-or-nil 0) => NIL

in earlier tests.

The design of the condition system is intended to yield reliable, 
modular behavior in dynamically composed call chains.
From: Vladimir Zolotykh
Subject: Re: handler-bind lookup procedure
Date: 
Message-ID: <3CB68D8B.7B697B5C@eurocom.od.ua>
Kent M Pitman wrote:
> 
[snip]

> But if the "more specific" function could trap something on an inner
> computation that was handled within that computation, you couldn't test
> the inner computation in isolation, and you'd get
> 
>  (one 0) => UNKNOWN
> 
> even though
> 
>  (reciprocal-or-nil 0) => NIL

Thank you Kent for excellent example. It clearly settled the matter.

-- 
Vladimir Zolotykh
From: Kent M Pitman
Subject: Re: handler-bind lookup procedure
Date: 
Message-ID: <sfwk7rd5oq5.fsf@shell01.TheWorld.com>
Vladimir Zolotykh <······@eurocom.od.ua> writes:

> Kent M Pitman wrote:
> > 
> [snip]
> 
> > But if the "more specific" function could trap something on an inner
> > computation that was handled within that computation, you couldn't test
> > the inner computation in isolation, and you'd get
> > 
> >  (one 0) => UNKNOWN
> > 
> > even though
> > 
> >  (reciprocal-or-nil 0) => NIL
> 
> Thank you Kent for excellent example. It clearly settled the matter.

No problem.  I hope you find the utility function useful as well.
It's often very useful to be able to compute that particular constant. ;)
From: Martin Simmons
Subject: Re: handler-bind lookup procedure
Date: 
Message-ID: <3cc0403a$0$233$ed9e5944@reading.news.pipex.net>
"Barry Margolin" <······@genuity.net> wrote in message
····················@paloalto-snr2.gtei.net...
> In article <·················@eurocom.od.ua>,
> Vladimir Zolotykh  <······@eurocom.od.ua> wrote:
> >Let me quote HyperSpec
> >
> >'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.'
> >
> >Seemed to me this concerns one handler-bind form. What should take place when
> >I have several of them nested? For example:
>
> The most recently established handler that matches the condition will be
> invoked.
>
> >(handler-bind ((specific-condition-2 #'(lambda (c) (print "specific"))))
> >  (handler-bind ((general-condition-2 #'(lambda (c) (print "general"))))
> >    (signal 'specific-condition-2)))
>
> This will print "general".

Or, to be precise, it will print "general" and "specific" and then return nil
because all of the handlers decline.
--
Martin Simmons
······@xanalys.com
rot13 to reply
From: Kent M Pitman
Subject: Re: handler-bind lookup procedure
Date: 
Message-ID: <sfwd6wv4m4y.fsf@shell01.TheWorld.com>
"Martin Simmons" <······@xanalys.com> writes:

> > >(handler-bind ((specific-condition-2 #'(lambda (c) (print "specific"))))
> > >  (handler-bind ((general-condition-2 #'(lambda (c) (print "general"))))
> > >    (signal 'specific-condition-2)))
> >
> > This will print "general".
> 
> Or, to be precise, it will print "general" and "specific" and then return nil
> because all of the handlers decline.

Heh.  Good (non)catch.