From: Marco Antoniotti
Subject: Using the USE-VALUE restart
Date: 
Message-ID: <zLmja.24$zV2.2280@typhoon.nyu.edu>
Hi

I am looking at doing essentially the following

(defun return-42 ()
   (1+ bar))

(return-42)
==> 42

I want to do that without setting BAR.

This means that I want to try to do somenting like

(defun return-42 ()
   (restart-bind ((use-value (lambda (x) x)))
     (handler-bind ((unbound-variable (lambda (uv) (use-value 41))))
       (1+ bar))))

Is the above a correct interpretation of the CLHS?

I am asking because LW 4.7.2 and CMUCL 18e do not work as expected. They 
insist on signaling an UNBOUND-VARIABLE error.

It is interesting to note that ACL 6.1 automatically sets up a USE-VALUE 
restart and does the rigth thing, although maybe non portably (cfr. the 
USE-VALUE entries in the CLHS), i.e.

#+allegro
(defun return-42 ()
    (handler-bind ((unbound-variable (lambda (uv) (use-value 41))))
       (1+ bar)))

does return 42.

Any ideas?  Please note that I am not interested in interactive behavior.

Cheers

--
Marco Antoniotti

From: Kent M Pitman
Subject: Re: Using the USE-VALUE restart
Date: 
Message-ID: <sfw1y0hx3wj.fsf@shell01.TheWorld.com>
Marco Antoniotti <·······@cs.nyu.edu> writes:

> Hi
> 
> I am looking at doing essentially the following
> 
> (defun return-42 ()
>    (1+ bar))
> 
> (return-42)
> ==> 42
> 
> I want to do that without setting BAR.
> 
> This means that I want to try to do somenting like
> 
> (defun return-42 ()
>    (restart-bind ((use-value (lambda (x) x)))
>      (handler-bind ((unbound-variable (lambda (uv) (use-value 41))))
>        (1+ bar))))
> 
> Is the above a correct interpretation of the CLHS?
> 
> I am asking because LW 4.7.2 and CMUCL 18e do not work as
> expected. They insist on signaling an UNBOUND-VARIABLE error.

UNBOUND-VARIABLE will be signaled, regardless. You just might handle it.

I tell people to stay away from RESTART-BIND if they don't know what 
they are doing. If RESTART-BIND declines (fails to transfer control), 
control continues from where the invoke-restart call happened (which 
is your handler, which then declines).  The whole point of 
RESTART-BIND is to transfer control and to do this you must say _where_ to
 transfer control to.  RESTART-BIND is useful only in a TINY set of
cases that are VERY obscure (such as the "Expunge this directory" restart
that sometimes you want to execute before ALSO executing another restart
like "Retry this file operation" when you get a "File system full" error.
The "Expunge this directory" operation should fail to transfer control
so that the debugger can take hold again and let the user run a second
restart, which is the real one...).  RESTART-BIND is, of course, also
needed in implementing RESTART-CASE.
If you only use RESTART-CASE, you'll generally win or at least will force
yourself to explicitly specify a return point, which will cause you to see
the real problem.

In the case you cite, the internal system setting up a RESTART-CASE 
correctly means it has ALSO set up a return point, which is (correctly)
inside the evaluation of the variable.  For you to do the same, you must
adorn each variable with a surrounding context, as in
 (+ (safely x) (safely y))
so that each call to safely can be a macro that expands into a return point
that your restart-bind [if corrected] could return to .. OR .. SAFELY
could just expand into a RESTART-CASE, obviating the need for a restart-bind.
Either way, it would be a lot of restart-cases or one RESTART-BIND and a lot
of dynamic return points.

(By contrast, both HANDLER-BIND and HANDLER-CASE are useful.  HANDLER-CASE
works more like other languages error trapping and is pretty boring but
still useful sometimes.  HANDLER-BIND is the only one that allows error
correction, which is something you don't see in too many other languages.)

I bet it's the case that LW and CMUCL use the store-value restart
instead of the use-value restart.  It's really a lot better.  Otherwise
you could get inconsistent values for this by returning different
values from repairs to (+ bar bar) that showed different values for
the two bar's.

Incidentally, the variable name "uv" is not a good one for unbound-variable
since uv also abbreviates use-value. ;)  Just spell things out or use
a variable like condition.  If you're determined to use a short name,
use 'c' for condition or 'e' for error.  Those are more common.

> It is interesting to note that ACL 6.1 automatically sets up a
> USE-VALUE restart and does the rigth thing, although maybe non
> portably (cfr. the USE-VALUE entries in the CLHS), i.e.

That means they also set it up correctly so you never got to your 
buggy RESTART-BIND because theirs was inside yours.

> #+allegro
> (defun return-42 ()
>     (handler-bind ((unbound-variable (lambda (uv) (use-value 41))))
>        (1+ bar)))
> 
> does return 42.
>
> Any ideas?  Please note that I am not interested in interactive behavior.

(defun return-42 ()
  (handler-bind ((unbound-variable
                   #'(lambda (c)
                       (let ((r (or (find-restart 'store-value c) ;preferred
                                    (find-restart 'use-value c))))
                         (when r (invoke-restart r 41))))))
   (1+ bar)))

I'm not sure why LW isn't setting up these restarts by their intended names.
You might try:

(defun return-42 ()
  (handler-bind ((unbound-variable
                   #'(lambda (c)
                       (let ((r (or (find-restart #-LW 'store-value
                                                  #+LW 'conditions::set
                                                  c) ;preferred
                                    (find-restart #-LW 'use-value
                                                  #+LW 'conditions::value))))
                         (when r (invoke-restart r 41))))))
   (1+ bar)))

and you might try sending a bug report.  I don't have CMUCL so can't try
that but it might yield to a similar treatment.

To debug your options, consider also:

(defun return-42 ()
  (handler-bind ((unbound-variable
                   #'(lambda (c)
                       (let ((r (or (find-restart 'store-value c) ;preferred
                                    (find-restart 'use-value c)
                                    (error "All I could find were ~S" 
                                           (compute-restarts c)))))
                         (when r (invoke-restart r 41))))))
   (1+ bar)))

That will at least get you an error break where you can examine the set of
available restarts.

Hope that helps.
From: Marco Antoniotti
Subject: Re: Using the USE-VALUE restart
Date: 
Message-ID: <vDgka.36$zV2.3427@typhoon.nyu.edu>
Kent M Pitman wrote:

> Marco Antoniotti  writes:
>
>
> >Hi
> >
> >I am looking at doing essentially the following
> >
> >(defun return-42 ()
> >   (1+ bar))
> >
> >(return-42)
> >==> 42
> >
> >I want to do that without setting BAR.
> >
> >This means that I want to try to do somenting like
> >
> >(defun return-42 ()
> >   (restart-bind ((use-value (lambda (x) x)))
> >     (handler-bind ((unbound-variable (lambda (uv) (use-value 41))))
> >       (1+ bar))))
> >
> >Is the above a correct interpretation of the CLHS?
> >
> >I am asking because LW 4.7.2 and CMUCL 18e do not work as
> >expected. They insist on signaling an UNBOUND-VARIABLE error.
>
>
> UNBOUND-VARIABLE will be signaled, regardless. You just might handle it.

That is what I am trying to do.  Handle the UNBOUND-VARIABLE by invoking 
the RESTART named USE-VALUE.


>
> I tell people to stay away from RESTART-BIND if they don't know what
> they are doing. If RESTART-BIND declines (fails to transfer control),
> control continues from where the invoke-restart call happened (which
> is your handler, which then declines). The whole point of
> RESTART-BIND is to transfer control and to do this you must say _where_ to
>  transfer control to.  RESTART-BIND is useful only in a TINY set of
> cases that are VERY obscure (such as the "Expunge this directory" restart
> that sometimes you want to execute before ALSO executing another restart
> like "Retry this file operation" when you get a "File system full" error.
> The "Expunge this directory" operation should fail to transfer control
> so that the debugger can take hold again and let the user run a second
> restart, which is the real one...).  RESTART-BIND is, of course, also
> needed in implementing RESTART-CASE.
> If you only use RESTART-CASE, you'll generally win or at least will force
> yourself to explicitly specify a return point, which will cause you to see
> the real problem.


Ok.  I get that.  I resorted to RESTART-BIND because RESTART-CASE did 
not seem to work in LW.  I admit not to have thought too much about it. 
  My earlier example code dealt with UNDEFINED-FUNCTION and similar code 
worked as expected in LW.


>
>
> In the case you cite, the internal system setting up a RESTART-CASE
> correctly means it has ALSO set up a return point, which is (correctly)
> inside the evaluation of the variable.  For you to do the same, you must
> adorn each variable with a surrounding context, as in
>  (+ (safely x) (safely y))
> so that each call to safely can be a macro that expands into a return 
> point
> that your restart-bind [if corrected] could return to .. OR .. SAFELY
> could just expand into a RESTART-CASE, obviating the need for a 
> restart-bind.


No.  Sorry, cannot work in my case, lest I code walk and do a 
recompilation of the code.  I'd wager that if I cannot achieve the 
effect with the RESTART machinery, then I am in very bad waters and the 
language is not helping me.

>
> Either way, it would be a lot of restart-cases or one RESTART-BIND and 
> a lot
> of dynamic return points.
>
> (By contrast, both HANDLER-BIND and HANDLER-CASE are useful.  HANDLER-CASE
> works more like other languages error trapping and is pretty boring but
> still useful sometimes.  HANDLER-BIND is the only one that allows error
> correction, which is something you don't see in too many other languages.)


Exactly.

> I bet it's the case that LW and CMUCL use the store-value restart
> instead of the use-value restart.  It's really a lot better.

I am working in LW (I lightly tested CMUCL).  I have some rationale for 
not wanting to use STORE-VALUE.

> Otherwise
> you could get inconsistent values for this by returning different
> values from repairs to (+ bar bar) that showed different values for
> the two bar's.

Good point.  However, I can take care of that in another way.

> Incidentally, the variable name "uv" is not a good one for 
> unbound-variable
> since uv also abbreviates use-value. ;)  Just spell things out or use
> a variable like condition.  If you're determined to use a short name,
> use 'c' for condition or 'e' for error.  Those are more common.


Ok.

>
>
> >It is interesting to note that ACL 6.1 automatically sets up a
> >USE-VALUE restart and does the rigth thing, although maybe non
> >portably (cfr. the USE-VALUE entries in the CLHS), i.e.
>
>
> That means they also set it up correctly so you never got to your
> buggy RESTART-BIND because theirs was inside yours.

That seems exactly to be the case.  But I am sorry to be so obdurate. 
But why is my RESTART-BIND buggy?

Is it because you are assuming that the implementation will *always* set 
up a (STORE-VALUE and - maybe - a USE-VALU) restart that will be 
dynamically shadowing mine?

> >#+allegro
> >(defun return-42 ()
> >    (handler-bind ((unbound-variable (lambda (uv) (use-value 41))))
> >       (1+ bar)))
> >
> >does return 42.
> >
> >Any ideas?  Please note that I am not interested in interactive behavior.
>
>
> (defun return-42 ()
>   (handler-bind ((unbound-variable
>                    #'(lambda (c)
>                        (let ((r (or (find-restart 'store-value c) 
> ;preferred
>                                     (find-restart 'use-value c))))
>                          (when r (invoke-restart r 41))))))
>    (1+ bar)))


Ok.  I could live with that.

>
> I'm not sure why LW isn't setting up these restarts by their intended 
> names.
> You might try:
>
> (defun return-42 ()
>   (handler-bind ((unbound-variable
>                    #'(lambda (c)
>                        (let ((r (or (find-restart #-LW 'store-value
>                                                   #+LW 'conditions::set
>                                                   c) ;preferred
>                                     (find-restart #-LW 'use-value
>                                                   #+LW 
> 'conditions::value))))
>                          (when r (invoke-restart r 41))))))
>    (1+ bar)))
>
> and you might try sending a bug report.


I did.

>   I don't have CMUCL so can't try
> that but it might yield to a similar treatment.
>
> To debug your options, consider also:
>
> (defun return-42 ()
>   (handler-bind ((unbound-variable
>                    #'(lambda (c)
>                        (let ((r (or (find-restart 'store-value c) 
> ;preferred
>                                     (find-restart 'use-value c)
>                                     (error "All I could find were ~S"
>                                            (compute-restarts c)))))
>                          (when r (invoke-restart r 41))))))
>    (1+ bar)))
>
> That will at least get you an error break where you can examine the set of
> available restarts.
>
> Hope that helps.


Yes it does.  Of course.

Thanks

--
Marco Antoniotti
From: Kaz Kylheku
Subject: Re: Using the USE-VALUE restart
Date: 
Message-ID: <cf333042.0304071401.4e1e1859@posting.google.com>
Marco Antoniotti <·······@cs.nyu.edu> wrote in message news:<·················@typhoon.nyu.edu>...
> Hi
> 
> I am looking at doing essentially the following
> 
> (defun return-42 ()
>    (1+ bar))
> 
> (return-42)
> ==> 42
> 
> I want to do that without setting BAR.
> 
> This means that I want to try to do somenting like
> 
> (defun return-42 ()
>    (restart-bind ((use-value (lambda (x) x)))
>      (handler-bind ((unbound-variable (lambda (uv) (use-value 41))))
>        (1+ bar))))

Oops; your RESTART-BIND is missing a non-local control transfer! You
need something like:

  (block nil
    (restart-bind ((use-value (lambda (x) (return x))))) ...)

or else use RESTART-CASE:

  (restart-case
    (blah ...)
    (use-value (x) x)

Otherwise your USE-VALUE restart closure returns back to the point
where USE-VALUE was invoked, which then causes the UNBOUND-VARIABLE
error handler to return, and hence the search for a handler continues!

Also note that if the USE-VALUE restart does not exist, then the
USE-VALUE form returns NIL; in that case you probably want the
behavior of continuing to search for a handler, but maybe you don't.


> I am asking because LW 4.7.2 and CMUCL 18e do not work as expected. They 
> insist on signaling an UNBOUND-VARIABLE error.

Heh, because the search for a handler continued, and made its way to
your REPL's interactive handler.

> It is interesting to note that ACL 6.1 automatically sets up a USE-VALUE 
> restart and does the rigth thing, although maybe non portably (cfr. the 
> USE-VALUE entries in the CLHS), i.e.
>
> #+allegro
> (defun return-42 ()
>     (handler-bind ((unbound-variable (lambda (uv) (use-value 41))))
>        (1+ bar)))
> 
> does return 42.

Probably because they correctly coded the restart to have a non-local
transfer which thereby handles the error. ;)