[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

restart to delete existing methods

Jim Newton

7/21/2015 11:18:00 AM

In slime, if I try to redefine a generic function with a different number of required arguments than it had previously, I get an error with the following restarts.
I was expecting there to be a "Delete existing methods" restart, but there isn't one.
Is this normal?

Has anyone created such a restart which I can add to my version of slime?

The lambda-list (VIEW IMAGE) is incompatible with existing methods of #<STANDARD-GENERIC-FUNCTION SHOW-IMAGE-WINDOW (1)>.
[Condition of type SIMPLE-ERROR]

Restarts:
0: [ABORT] Abort compilation.
1: [*ABORT] Return to SLIME's top level.
2: [ABORT] abort thread (#<THREAD "worker" RUNNING {11ACB042F3}>)

Backtrace:
0: (SB-PCL::SET-ARG-INFO #<STANDARD-GENERIC-FUNCTION SHOW-IMAGE-WINDOW (1)> :NEW-METHOD NIL :LAMBDA-LIST (VIEW IMAGE) :ARGUMENT-PRECEDENCE-ORDER NIL)
1: ((:METHOD REINITIALIZE-INSTANCE :AROUND (STANDARD-GENERIC-FUNCTION)) #<STANDARD-GENERIC-FUNCTION SHOW-IMAGE-WINDOW (1)> :LAMBDA-LIST (VIEW IMAGE) :DEFINITION-SOURCE #S(SB-C:DEFINITION-SOURCE-LOCATION ..
2: (SB-PCL::REAL-ENSURE-GF-USING-CLASS--GENERIC-FUNCTION #<STANDARD-GENERIC-FUNCTION SHOW-IMAGE-WINDOW (1)> SHOW-IMAGE-WINDOW #<unavailable &REST argument> :ENVIRONMENT #<unused argument> :LAMBDA-LIST #<..
3: (SB-FASL::LOAD-FASL-GROUP #S(SB-FASL::FASL-INPUT :STREAM #<SB-SYS:FD-STREAM for "file /private/var/tmp/tmp.fasl" {11ACB1AC93}> :TABLE #(19 #<PACKAGE "SB-PCL"> SB-PCL::COMPILE-OR-LOAD-DEFGENERIC #<PACK..
4: (SB-FASL::LOAD-AS-FASL #<SB-SYS:FD-STREAM for "file /private/var/tmp/tmp.fasl" {11ACB1AC93}> NIL NIL)
5: ((FLET SB-FASL::LOAD-STREAM :IN LOAD) #<SB-SYS:FD-STREAM for "file /private/var/tmp/tmp.fasl" {11ACB1AC93}> T)
6: (LOAD #P"/private/var/tmp/tmp.fasl" :VERBOSE NIL :PRINT NIL :IF-DOES-NOT-EXIST T :EXTERNAL-FORMAT :DEFAULT)
7: ((FLET SWANK/BACKEND:CALL-WITH-COMPILATION-HOOKS :IN "/Users/jnewton/sw/slime/swank/sbcl.lisp") #<CLOSURE (LAMBDA NIL :IN SWANK/BACKEND:SWANK-COMPILE-STRING) {11ACB19D0B}>)
8: ((FLET SWANK/BACKEND:SWANK-COMPILE-STRING :IN "/Users/jnewton/sw/slime/swank/sbcl.lisp") "(defgeneric show-image-window (view image)) ..)
9: ((LAMBDA NIL :IN SWANK:COMPILE-STRING-FOR-EMACS))
10: ((LAMBDA NIL :IN SWANK::COLLECT-NOTES))
--more--
2 Answers

Zach Beane

7/21/2015 12:05:00 PM

0

Jim Newton <jimka.issy@gmail.com> writes:

> In slime, if I try to redefine a generic function with a different number of required arguments than it had previously, I get an error with the following restarts.
> I was expecting there to be a "Delete existing methods" restart, but there isn't one.
> Is this normal?
>
> Has anyone created such a restart which I can add to my version of slime?

It's normal for SBCL. It's not specific to SLIME. Other Lisps provide a
richer set of restarts.

I can't find the document right now (so maybe I'm getting the details
wrong), but when SBCL was created from CMUCL, many things that made the
process more complicated were simply removed. That included many
restarts, but also things like Hemlock, WIRE, and the interpreter.

Zach

Pascal J. Bourguignon

7/21/2015 3:27:00 PM

0

Jim Newton <jimka.issy@gmail.com> writes:

> Has anyone created such a restart which I can add to my version of
> slime?

Restarts cannot be created independently of the code that they try to
"correct".

Even HANDLER-BIND, which handles the errors in the dynamic environment
where they occur, can in general do very little to "correct" the error,
because the error handler may only do two things: handle the condition,
or decline it.

Declining means the handler returns (and therefore handler-bind goes on
searching handlers, until one is found that handles, or none in which
case error enters the debugger, and signal returns. Notice: if the
condition has been signaled by SIGNAL instead of ERROR, then SIGNAL
returns and the execution continues. But this means that something has
been programmed for this case at the place where the condition is
signaled!

Handling means the handler performs a non-local exit. This may occur if
the handler signals a condition itself (including an error), in which
case handlers are searched again in the outer scope. The handler may
perform a non-local exit to a block it knows with RETURN-FROM or
THROWing an object that will be caught, or jumping with GO to a label
established by a TAGBODY in scope (outside of the HANDLER-BIND).

Finally, the handler may perform a non-local exit by invoking a
restart. It may list the restarts active in the dynamic environment, it
may find one, it may invoke one. When invoking a restart, the function
corresponding to the restart established in the restart-bind form may
either perform a non-local exit, or return.

(restart-bind ((test (lambda (msg)
(print msg)
42)))
(handler-bind ((error (lambda (c)
(print `(restart returned
,(invoke-restart 'test (list :condition c))))
33)))
(print `(signal returned ,(signal 'error)))
(print 'done)
(terpri)))

prints:
(:condition #<error #x30200216459D>)
(restart returned 42)
(signal returned nil)
done
--> nil


Those are nice nice mechanisms, and they will let you do very
sophisticated control flow in your applications.



However, in the case of the relations with the implementation, there's a
little problem: error cases, and conditions are not specified precisely
enough by the standard to allow correction of errors from outside of the
implementation. There are two parts in this problems:

- the standard doesn't specify always that implementation should signal
a condition, or what condition it should signal. For example, in the
case in question, defgeneric is specified to signal a condition of
type ERROR:

If a defgeneric form is evaluated and some methods for that generic
function have lambda lists that are not congruent with that given in
the defgeneric form, an error of type error is signaled.

which is a very generic error condition, so implementations may not
provide enough information in the condition to let the handler (of the
ERROR condition) know that the problem is with a defgeneric, what
generic function is concerned, what new lambda list is desired. Each
implementation could define subclasses of the ERROR condition to
provide all the details about the errors, but this wouldn't be
standard anyways, so you could difficultly rely on it.

- even if the condition was full of information about the error, it
won't always be possible to correct the error by mutating the data
provided in the condition. Indeed, often you would have to perform a
jump into a lexical scope that is in side the implementation (either
to some place "after" the signaling, or to some place "before" the
signaling, to "try again"). This is definitely not possible.
Handlers, and restart functions, may only decline (simply returning),
or handle by performing a non-local exit, which will be in their outer
lexical or dynamic scopes.


Therefore, the only place where error correcting code can occur, whether
thru a normal condition handler, or thru a restart function, is close to
where the error is signaled, deep inside the implementation. The
restarts and the error correction code for errors signaled inside the
implementation will have to be provided by the implementation.

Similarly, restarts and the error correction code for errors signaled
inside a library should be provided by the library itself.

However, for an application or a library, it is possible to provide
restarts and error correction functions that are quite general, and in
handlers or restarts installed in a very wide dynamic scope, assuming
that the application or library define conditions with all the data
required by the error correcting functions, and given some knowledge and
provision for retrying or continuing the operation deep inside the
application or library. Notably, the code can provide the restarts that
will abstract away the non-local exit points that are valid locally for
error corrections. That is, the schema will be:

(block :abort
(handler-bind
((some-specific-application-error
(lambda (condition)
(multiple-value-bind (restart arguments) (analyze-the-error condition)
(apply (function invoke-restart)
(find-restart restart condition)
arguments)
;; could not handle it with restarts
(return-from :abort)))))
(do-something)))


and deep into the application do-something will eventually call some
internal function that will signal some-specific-application-error.
This is this internal function that will install the restarts to handle
the error in various pre-programmed ways:

(defun some-internal-operation (&rest arguments)
(restart-case
(let ((some-internal-data 42))
(tagbody
:from-the-beginning
(do-something)
:try-again
(restart-case
(progn
(start-it)
(when (something-bad-happens-p)
(error 'some-specific-application-error
:some-data data
:and-also other-data
:and-some-context context))
(complete-it))
(bump-internal-data ()
(incf some-internal-data)
;; "local" non-local exit:
;; We'll get out of the ERROR call,
;; but we jump inside the local tagbody
(go :from-the-beginning))
(try-again ()
(go :try-again))
(ignore-it ()
(go :ignore-it)))
:ignore-it
(finally-do-something)))
(abort-internal-operation (condition)
(error 'aborted-internal-operation
:operation 'some-internal-operation
:arguments arguments
:reason 'restart-invoked
:original-condition condition))))

The outter error handler could still mutate the data passed in the
some-specific-application-error condition and invoke the try-again or
bump-internal-data restarts, but only as long as such a restart is
provided.

It may also be a continue restart (eg. set up by CERROR).

The internal code could explicitely use SIGNAL instead of ERROR and let
the handler mutate the data, and deny, but using SIGNAL could be
dangerous because it allows for no handler at all, so the situation may
have not changed when it returns. (Of course, error correction code
could be put after the SIGNAL call to handle this occurence).


In conclusion, conditions and restarts are not a magic wand to correct
errors from outside of libraries (even less from outside of the
implementation), but they're still nice mechanisms to provide such error
correction code, or at least, provide hooks (re-try or re-entry points)
for application provided error correction code.

If the handler cannot correct the error automatically from the outside,
at least it can choose amongst the options provided by the functions
from where the errors are signaled; a library or an application could
provide a rich ontology of conditions and restarts so errors handlers
could do some smart work choosing the right restart depending on the
current state of the application.

And of course, it is always possible to use very generic outside
restarts, to abort the current action and recover at a higher level,
counting on systematic use of (explicit or implicit) unwind-protect
forms to clean up everything.


Finally, there is of course the possibility in a handler to present the
choice to the user and to invoke restarts interactively (a restart may
provide some interactive dialog function to let the user enter
parameters or new values), but even if we don't consider a sonde that's
half a day.light away, you will often want to avoid dropping into the
debugger or otherwise require user intervention to select a restart.
You might prefer to spend your week-end at home, instead of being called
because your program is requiring your attention to select a restart.

--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk