From: Vladimir Zolotykh
Subject: RESTART-CASE :test function argument
Date: 
Message-ID: <opspbfyzxh4w83rv@algow.eurocom.od.ua>
The form

   (restart-case (error "foo")
     (nil ()
       :report "Something"
       :test (lambda (c) (print c) t)))

outputs

   Error: foo
     [condition type: simple-error]

   nil ; ***
   Restart actions (select using :continue):
    0: Something
    1: Return to Top Level (an "abort" restart).
    2: Abort entirely from this (lisp) process.

All is fine except the line marked ***. Why is it nil?
In HyperSpec I can read

   "The value supplied by :test value must be a suitable argument to
   function. (function value) is evaluated in the current lexical
   environment. It should return a function of one argument, the
   condition, that returns true if the restart is to be considered
   visible."

Hence I concluded (wrongly) that C in the example above should be the
CONDITION, in this case an object of the SIMPLE-ERROR type. Was I
wrong? What actually C is? And are there cases when it is anything but
NIL?

My intention was to filter some of my restarts which applicable only
if certain types of errors occur inside restartable form and I thought
:test function suits me the best for that, it turned out however not
so good. Where I was wrong, would you kindly tell me?

Thanks in advance




-- 
Vladimir Zolotykh

From: Juliusz Chroboczek
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <7i3btpnku0.fsf@lanthane.pps.jussieu.fr>
>    (restart-case (error "foo")
>      (nil ()
>        :report "Something"
>        :test (lambda (c) (print c) t)))

> outputs

>    Error: foo
>      [condition type: simple-error]
>
>    nil ; ***
>    Restart actions (select using :continue):

> All is fine except the line marked ***. Why is it nil?

It is my (possibly erroneous) understanding that the descriptions of
the :TEST argument to RESTART-CASE and the :TEST-FUNCTION argument to
RESTART-BIND are wrong -- they fail to mention that the argument can
be NIL.

In any case, they are inconsistent with COMPUTE-RESTARTS, which takes
an argument of type (OR NULL CONDITION):

   When condition is non-nil, only those restarts are considered that
   are either explicitly associated with that condition, or not
   associated with any condition; that is, the excluded restarts are
   those that are associated with a non-empty set of conditions of which
   the given condition is not an element. If condition is nil, all
   restarts are considered.

So your test function should probably expect to get either a condition
or NIL as argument.  (At any rate, if it doesn't it will break at
least under CMUCL).

If people can explain how COMPUTE-RESTARTS of NIL is supposed to work
if the test function associated to a restart cannot take NIL, I'm very
much interested.

                                        Juliusz
From: Kalle Olavi Niemitalo
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <87hdi46453.fsf@Astalo.kon.iki.fi>
Juliusz Chroboczek <···@pps.jussieu.fr> writes:

> It is my (possibly erroneous) understanding that the descriptions of
> the :TEST argument to RESTART-CASE and the :TEST-FUNCTION argument to
> RESTART-BIND are wrong -- they fail to mention that the argument can
> be NIL.

Section 9.1.4.2.3 (Restart Tests) and the glossary entry for
"applicable restart" say explicitly that the argument can be nil.
From: Vladimir Zolotykh
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <opspe5cgvy4w83rv@algow.eurocom.od.ua>
How then I can associate restart with the condition? In this case
argument of the :test function should be the condition, right?
I've tried

(define-condition my-condition () ())

(restart-case
     (with-condition-restarts 'my-condition
	(list (find-restart 'my-restart))
       (error 'my-condition))
   (my-restart ()
       :report "Do something."
       :test (lambda (c) (print c) t)))

Yet the :test function is still called with NIL as an argument.

On Sun, 17 Apr 2005 23:40:23 +0200, Juliusz Chroboczek  
<···@pps.jussieu.fr> wrote:

>>    (restart-case (error "foo")
>>      (nil ()
>>        :report "Something"
>>        :test (lambda (c) (print c) t)))
>
>> outputs
>
>>    Error: foo
>>      [condition type: simple-error]
>>
>>    nil ; ***
>>    Restart actions (select using :continue):
>
>> All is fine except the line marked ***. Why is it nil?
>
> It is my (possibly erroneous) understanding that the descriptions of
> the :TEST argument to RESTART-CASE and the :TEST-FUNCTION argument to
> RESTART-BIND are wrong -- they fail to mention that the argument can
> be NIL.
>
> In any case, they are inconsistent with COMPUTE-RESTARTS, which takes
> an argument of type (OR NULL CONDITION):
>
>    When condition is non-nil, only those restarts are considered that
>    are either explicitly associated with that condition, or not
>    associated with any condition; that is, the excluded restarts are
>    those that are associated with a non-empty set of conditions of which
>    the given condition is not an element. If condition is nil, all
>    restarts are considered.
>
> So your test function should probably expect to get either a condition
> or NIL as argument.  (At any rate, if it doesn't it will break at
> least under CMUCL).
>
> If people can explain how COMPUTE-RESTARTS of NIL is supposed to work
> if the test function associated to a restart cannot take NIL, I'm very
> much interested.
>
>                                         Juliusz



-- 
Vladimir Zolotykh
From: Juliusz Chroboczek
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <7ifyxn8vjk.fsf@lanthane.pps.jussieu.fr>
"Vladimir Zolotykh" <······@eurocom.od.ua> writes:

> How then I can associate restart with the condition? In this case
> argument of the :test function should be the condition, right?

The condition or NIL.  Just return T in case the argument is NIL.

                                        Juliusz
From: Vladimir Zolotykh
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <opspg6c9or4w83rv@algow.eurocom.od.ua>
On Tue, 19 Apr 2005 02:22:39 +0200, Juliusz Chroboczek  
<···@pps.jussieu.fr> wrote:

> "Vladimir Zolotykh" <······@eurocom.od.ua> writes:
>
>> How then I can associate restart with the condition? In this case
>> argument of the :test function should be the condition, right?
>
> The condition or NIL.  Just return T in case the argument is NIL.
Of couse I can, but I like to know what I'm doing, to understand what's  
happening.
For instance, I'd like to see the case when :TEST function receives a  
condition not NIL.
>
>                                         Juliusz



-- 
Vladimir Zolotykh
From: Kalle Olavi Niemitalo
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <87br8b62di.fsf@Astalo.kon.iki.fi>
"Vladimir Zolotykh" <······@eurocom.od.ua> writes:

>      (with-condition-restarts 'my-condition
> 	(list (find-restart 'my-restart))
>        (error 'my-condition))

The first argument of WITH-CONDITION-RESTARTS must be a form
whose value is a condition.  The value of your form is a symbol.
Condition designators (9.1.2.1) are not allowed here.
From: Vladimir Zolotykh
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <opspg57dg04w83rv@algow.eurocom.od.ua>
On Tue, 19 Apr 2005 03:23:21 +0300, Kalle Olavi Niemitalo <···@iki.fi>  
wrote:

> "Vladimir Zolotykh" <······@eurocom.od.ua> writes:
>
>>      (with-condition-restarts 'my-condition
>> 	(list (find-restart 'my-restart))
>>        (error 'my-condition))
>
> The first argument of WITH-CONDITION-RESTARTS must be a form
> whose value is a condition.  The value of your form is a symbol.
> Condition designators (9.1.2.1) are not allowed here.
OK, I've tried to fix that

(define-condition my-condition () ())

(let ((cn (make-condition 'my-condition)))
(restart-case
     (with-condition-restarts cn
	(list (find-restart 'my-restart))
       (error cn))
   (my-restart ()
       :report "Do something."
       :test (lambda (c) (format t "c=~S~%" c) t)))
)

Unfortunately this again gives me two NILs e.g.

c=nil
Error: #<my-condition @ #x7179780a>
   [condition type: my-condition]
c=nil

Restart actions (select using :continue):
  0: Do something.
  1: Return to Top Level (an "abort" restart).
  2: Abort entirely from this (lisp) process.
[1] cl-user(12):

Were I'm wrong again?

By the bye, in the Common Lisp The Language 2d ed on page 904
(29.4.7 Establishing Restarts) I can read
"As a special case, if the expression is a list whose car is signal, error,
cerror, or warn, then with-condition-restarts is implicityly used to  
associate
the restarts with the condition to be signalled"
According to this even my first posted sample must have associated
the restarts with the condition, right?



-- 
Vladimir Zolotykh
From: Kalle Olavi Niemitalo
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <878y3e5zeo.fsf@Astalo.kon.iki.fi>
"Vladimir Zolotykh" <······@eurocom.od.ua> writes:

> Unfortunately this again gives me two NILs e.g.
>
> c=nil
> Error: #<my-condition @ #x7179780a>
>    [condition type: my-condition]
> c=nil

Which CL implementation is that?
I get c=NIL c=#<MY-CONDITION {480419ED}> in CMUCL 18e,
c=NIL c=#<MY-CONDITION {90FE621}> in SBCL 0.8.20.5, and
c=NIL c=#<MY-CONDITION #x203E58E6> in CLISP 2.33.2.

> According to this even my first posted sample must have associated
> the restarts with the condition, right?

Right; MACROEXPAND should show this.  In SBCL, the output order
is better if you put a (finish-output) after the (print c).
From: Vladimir Zolotykh
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <opspiuq7xe4w83rv@algow.eurocom.od.ua>
On Tue, 19 Apr 2005 22:39:43 +0300, Kalle Olavi Niemitalo <···@iki.fi>  
wrote:

> "Vladimir Zolotykh" <······@eurocom.od.ua> writes:
>
>> Unfortunately this again gives me two NILs e.g.
>>
>> c=nil
>> Error: #<my-condition @ #x7179780a>
>>    [condition type: my-condition]
>> c=nil
>
> Which CL implementation is that?
ACL70 and it prints c=NIL only once for the form
w/o with-condition-restarts. So it seems like a bug, ins't it?

> I get c=NIL c=#<MY-CONDITION {480419ED}> in CMUCL 18e,
> c=NIL c=#<MY-CONDITION {90FE621}> in SBCL 0.8.20.5, and
> c=NIL c=#<MY-CONDITION #x203E58E6> in CLISP 2.33.2.
>
>> According to this even my first posted sample must have associated
>> the restarts with the condition, right?
>
> Right; MACROEXPAND should show this.  In SBCL, the output order
> is better if you put a (finish-output) after the (print c).



-- 
Vladimir Zolotykh
From: Kent M Pitman
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <ud5skqiot.fsf@nhplace.com>
"Vladimir Zolotykh" <······@eurocom.od.ua> writes:

> On Tue, 19 Apr 2005 03:23:21 +0300, Kalle Olavi Niemitalo <···@iki.fi>
> wrote:
> 
> > "Vladimir Zolotykh" <······@eurocom.od.ua> writes:
> >
> >>      (with-condition-restarts 'my-condition
> >> 	(list (find-restart 'my-restart))
> >>        (error 'my-condition))
> >
> > The first argument of WITH-CONDITION-RESTARTS must be a form
> > whose value is a condition.  The value of your form is a symbol.
> > Condition designators (9.1.2.1) are not allowed here.
> OK, I've tried to fix that
> 
> (define-condition my-condition () ())
> 
> (let ((cn (make-condition 'my-condition)))
> (restart-case
>      (with-condition-restarts cn
> 	(list (find-restart 'my-restart))
>        (error cn))
>    (my-restart ()
>        :report "Do something."
>        :test (lambda (c) (format t "c=~S~%" c) t)))
> )
> 
> Unfortunately this again gives me two NILs e.g.
> 
> c=nil
> Error: #<my-condition @ #x7179780a>
>    [condition type: my-condition]
> c=nil
> 
> Restart actions (select using :continue):
>   0: Do something.
>   1: Return to Top Level (an "abort" restart).
>   2: Abort entirely from this (lisp) process.
> [1] cl-user(12):
> 




> Were I'm wrong again?
 
I don't have time at this instant to analyze your specific problem in
detail, but you might want to notice X3J13 cleanup issue CONDITION-RESTARTS,
which discusses this kind of thing in detail.

  http://www.lispworks.com/documentation/HyperSpec/Issues/iss075_w.htm

> By the bye, in the Common Lisp The Language 2d ed on page 904
> (29.4.7 Establishing Restarts) I can read
> "As a special case, if the expression is a list whose car is signal, error,
> cerror, or warn, then with-condition-restarts is implicityly used to
> associate
> the restarts with the condition to be signalled"
> According to this even my first posted sample must have associated
> the restarts with the condition, right?

Unless your specific implementation says it conforms to CLTL2, please
don't use that as a reference for behavior.  [It's fine if you want to
learn general concepts from there, since perhaps in some cases Steele has
more eloquent explanations/descriptions in CLTL2 than I do in ANSI CL],
but (a) we made numerous technical changes between the time of CLTL2
and ANSI CL and (b) CLTL2 is not even in the ancestry of ANSI CL.  

CLTL(1) was written by Steele but was carefully checked to correspond
to committee decisions and was ultimately endorsed by the committee.
CLTL1 was also the base document for ANSI CL, although as you can see
was heavily changed over the next decade.  CLTL2 was based on a
checkpoint of CLTL1 and augmented by Steele's attempt to checkpoint
the internal process at a time that he did not coordinate with the
committee in any official way.  He did a fine job but his work was not
official, was not reviewed by the committee, was not endorsed by the
committee, and was not coordinated in any way with the committee.  We
continued to make changes after his checkpoint that were not
coordinated with his document, including not just adding things but
removing them.  As such, it's not like CLTL2 is a superset of CLTL1
and ANSI CL is a superset of CLTL2.  Rather, CLTL2 is an incompatible
subset of CLTL1, and is not logically/coherently related to ANSI CL
other than in the trivial sense that it began from CLTL1, just as ANSI
CL did.  Steele acknowledges this in, if memory serves, his second 
edition preface, but most people overlook it.

CLTL2 was adopted by some implementations as an interim standard, over
the objections of both the committee and Steele himself, because of
the practical need to adhere to something other than CLTL1.  But at
some point, I think all the major implementations agreed to at least
"purport to conform" to ANSI CL (i.e., they don't profess not to have
bugs, but rather they are willing to receive bug reports about such
non-conformances as they are discovered).    There were other 
implementations that never used CLTL2 as an interim guide, but instead
preferred one or more of the draft proposed standards (dpANS's).

The Common Lisp HyperSpec (a.k.a CLHS, available from LispWorks.com)
is a derivative work of ANSI Common Lisp, and is, as a consequence,
authoritative as to what ANSI requires.
From: Juliusz Chroboczek
Subject: Re: RESTART-CASE :test function argument
Date: 
Message-ID: <7ik6mz8vkh.fsf@lanthane.pps.jussieu.fr>
>> It is my (possibly erroneous) understanding that the descriptions of
>> the :TEST argument to RESTART-CASE and the :TEST-FUNCTION argument to
>> RESTART-BIND are wrong -- they fail to mention that the argument can
>> be NIL.

> I suspect it's CMUCL that's broken,

In that case, so are SBCL, CLISP and Lispworks.

Try this:

  (restart-case (compute-restarts) 
    (alamakota () 
      :test (lambda (c) 
              (when (null c) 
                (format t "Test function called with NIL"))
              t)
      (throw 'alamakota nil)))

> and that the test function should only be called if the argument is
> non-NIL (if it is NIL, the funcall can be skipped and the result
> assumed to be T -- "if condition is nil, all restarts are considered")

Hmm...  I would think that it should be possible for a restart to be
disabled altogether, irrespective of the condition.

                                        Juliusz