From: Vladimir V. Zolotych
Subject: RESTART-BIND
Date: 
Message-ID: <3A70694F.DD2DA7EB@eurocom.od.ua>
This is a multi-part message in MIME format.
--------------439C1F136578557DADBABA68
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

  Hello

Two questions about RESTART-BIND. Both to behavior I can't understand.

The affected code

;; The first definition of FOO is obsoleted, but saved here to explain
;; the problem.

(defun foo (a) (format t "~S" a)) 
(defun foo (a &optional (stream t)) (format stream "~S" a))

(restart-bind ((nil #'(lambda () (foo 111))
		    :report-function
		    #'(lambda (stream) (foo 'a stream)))
	       (nil #'(lambda () (foo 2222))
		    :report-function
		    #'(lambda (stream) (foo 'b stream))))
  (loop
   (cerror "c" "d")))

My actions exactly (excuse me, this is needed to explain what I want to
ask).

CMU Common Lisp 18c, running on Olla
.......
* (defun foo (a) (format t "~S" a))
FOO
* (restart-bind ......) ; exactly the same as shown above

Here I skips trash output..., because I call wrong version of FOO.
Now I redefine FOO properly.

* (defun foo (a &optional (stream t)) (format stream "~S" a))
FOO
* (foo 1 t)
1
NIL
* (restart-bind ......) ; 

  (FOO 'A STREAM)
Warning: Function called with two arguments, but wants exactly one.

What happens ?

If I 

* (quit)
$ lisp
.....
* (defun foo (a &optional (stream t)) (format stream "~S" a))
FOO
* (restart-bind .......) ; exactly the same as before

All works and here comes my second question.

I see four choices:

  0: [CONTINUE] c
  1:            A
  2:            B
  3: [ABORT   ] Return to Top-Level.

Choices 0, 1 works as I expected (choice 1 prints 111).
But if I enter 2 to 0] prompt I see

0] 2

2
0] 

Probably I don't understand the RESTART-BIND functionality. Please
explain me what's wrong.

Thanks for your patience.


-- 
Vladimir Zolotych                         ······@eurocom.od.ua
--------------439C1F136578557DADBABA68
Content-Type: text/x-vcard; charset=us-ascii;
 name="gsmith.vcf"
Content-Transfer-Encoding: 7bit
Content-Description: Card for Vladimir V. Zolotych
Content-Disposition: attachment;
 filename="gsmith.vcf"

begin:vcard 
n:Zolotych;Valdimir V.
x-mozilla-html:FALSE
adr:;;;;;;
version:2.1
·····················@eurocom.od.ua
x-mozilla-cpt:;0
fn:Valdimir V. Zolotych
end:vcard

--------------439C1F136578557DADBABA68--

From: Barry Margolin
Subject: Re: RESTART-BIND
Date: 
Message-ID: <Jg_b6.22$b_3.241@burlma1-snr2>
In article <·················@eurocom.od.ua>,
Vladimir V. Zolotych <······@eurocom.od.ua> wrote:
>Two questions about RESTART-BIND. Both to behavior I can't understand.
>
>The affected code
>
>;; The first definition of FOO is obsoleted, but saved here to explain
>;; the problem.
>
>(defun foo (a) (format t "~S" a)) 
>(defun foo (a &optional (stream t)) (format stream "~S" a))
>
>(restart-bind ((nil #'(lambda () (foo 111))
>		    :report-function
>		    #'(lambda (stream) (foo 'a stream)))
>	       (nil #'(lambda () (foo 2222))
>		    :report-function
>		    #'(lambda (stream) (foo 'b stream))))
>  (loop
>   (cerror "c" "d")))
>
>My actions exactly (excuse me, this is needed to explain what I want to
>ask).
>
>CMU Common Lisp 18c, running on Olla
>.......
>* (defun foo (a) (format t "~S" a))
>FOO
>* (restart-bind ......) ; exactly the same as shown above
>
>Here I skips trash output..., because I call wrong version of FOO.
>Now I redefine FOO properly.
>
>* (defun foo (a &optional (stream t)) (format stream "~S" a))
>FOO
>* (foo 1 t)
>1
>NIL
>* (restart-bind ......) ; 
>
>  (FOO 'A STREAM)
>Warning: Function called with two arguments, but wants exactly one.
>
>What happens ?

This makes no sense.  I could understand it if you had put the RESTART-BIND
into a function and had declared FOO to be INLINE, because that would have
open-coded the original version of FOO (although then the error should have
been noticed at compile time).  I can't think of any way that a
RESTART-BIND typed at top-level could somehow resurrect the old binding of
FOO.

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, 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: Pierre R. Mai
Subject: Re: RESTART-BIND
Date: 
Message-ID: <877l3j8ekq.fsf@orion.bln.pmsf.de>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> Two questions about RESTART-BIND. Both to behavior I can't understand.

Actually the behaviour you don't understand is not related to
restart-bind, but to implementation-specific bugs in CMU CL's
compiler/info-database and the debugger interface.  So not
understanding it seems valid behaviour ;).  Below come some longish
explanations for the bugs, which you can read if you are interested in
some of the interna of CMU CL and the root causes of your bugs.  If
not, here's the executive summary of the two bugs:

Bug 1 is a harmless bug, which might take a little time to fix,
Bug 2 is a harmless bug, which can be circumvented by using the
RESTART debugger command (type HELP at the debugger prompt for
explanations) to invoke restarts, instead of relying on the shortcut
debugger commands (0, 1, etc.).  A fix for that bug is underway to the
CMU CL implementation mailing list.

Longish explanations:

> The affected code
> 
> ;; The first definition of FOO is obsoleted, but saved here to explain
> ;; the problem.
> 
> (defun foo (a) (format t "~S" a)) 
> (defun foo (a &optional (stream t)) (format stream "~S" a))

That's all that is needed to illustrate your problem, e.g.

* (defun foo (a) (list a))

FOO
* (let ((x 1)) (foo x))

(1)
* (defun foo (a  b) (list a b))

FOO
* (let ((x 1)) (foo x 2))

In: LET ((X 1))
  (FOO X 2)
Warning: Function called with two arguments, but wants exactly one.

(1 2)

The let constructs are needed in this example to cause CMU CL to use
the (IR1-stage of the) compiler for the expressions.  To explain:  CMU
CL has two "interpreters".  One very simple one, that works directly
on the source and which can evaluate simple things by itself (like
evaluating a functional call form, etc.), but that has to use the
compiler-based for more complex forms, like e.g. let-forms.  The
compiler-based interpreter uses the first phases of the compiler to
convert the source to its internal IR1 representation, which then
gets evaluated.  This interpreter by virtue of the IR1 phases of the
compiler does full cross-checking of forms, and hence only if that
interpreter is used will you get the above warning.

Now what happens?  CMU CL fails to update its internal info database
on the second foo with the new functions signature, i.e. its function
type:

* (ext:info function type 'foo)

#<FUNCTION-TYPE (FUNCTION (T) *)>
NIL
* (kernel:type-specifier *)

(FUNCTION (T) *)

This happens because the info database uses a cache, and that cache is
not invalidated, hence the information in the cache will be returned,
although it is out-of-date.  If we clear the cache, we will get the
correct info:

* (c::info-cache-clear)

EXTENSIONS::%UNDEFINED%
* (ext:info function type 'foo)

#<FUNCTION-TYPE (FUNCTION (T T) LIST)>

And now our code will ir1-convert without warnings:

* (let ((x 1)) (foo x 2))

(1 2)

To summarize, this is a small bug in the CMU CL info-caching code,
IMHO, and I'll pass this on to the CMU CL implementation list, so that
it can be properly resolved.

On to your second problem:

> I see four choices:
> 
>   0: [CONTINUE] c
>   1:            A
>   2:            B
>   3: [ABORT   ] Return to Top-Level.
> 
> Choices 0, 1 works as I expected (choice 1 prints 111).
> But if I enter 2 to 0] prompt I see
> 
> 0] 2
> 
> 2
> 0] 
> 
> Probably I don't understand the RESTART-BIND functionality. Please
> explain me what's wrong.

It's not the restart-bind you don't understand, it is a bug in CMU
CL's debugger interface.  The "normal" way to invoke a restart is via
the RESTART debugger command, and this works correctly in (a slightly
changed version of) your example:

* (restart-bind ((nil #'(lambda () (format t "Invoked restart A.~%"))       
                      :report-function #'(lambda (x) (format x "Restart A.")))
                 (nil #'(lambda () (format t "Invoked restart B.~%"))
                      :report-function #'(lambda (x) (format x "Restart B."))))
    (error "Error C"))



Error in function "Top-Level Form":  Error C

Restarts:
  0:         Restart A.
  1:         Restart B.
  2: [ABORT] Return to Top-Level.

Debug  (type H for help)

("Top-Level Form")[:TOP-LEVEL]
Source: (ERROR "Error C")
0] RESTART 0
Invoked restart A.

0] RESTART 1
Invoked restart B.

0] 

But the help of the debugger promisses you that the debugger will also
establish debugger commands for all active restarts, both for their
name, and for their number.  So typing 0, 1 or 2 should work, as
should ABORT (and maybe NIL, but see below). Well 0 and 2 will work,
abort, too, and NIL will invoke the first restart, too.

Why doesn't 1 work?  Because of a glitch in the CMU CL debugger code,
if there are two restarts with the same name (nil in this case), only
the first will get any debugger commands established.  So 1 is no
debugger command, and will thus be evaluated like a normal lisp form,
yielding 1.

A bug fix for this second bug should already be underway by the time
you read this.

To summarize again:  Your understanding of CL constructs is not to
blame for any of these problems, they are both bugs in CMU CL.

> Thanks for your patience.

Thanks for your patience in reporting your experiences with CMU CL,
and sorry about the bugs.

Regs, Pierre.

-- 
Pierre R. Mai <····@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