General list: use a handler in different packages

I have the following lisp code:

;;; hop.lisp (defpackage #:hop (:use #:cl )) (in-package :hop) (export 'hop) (defun hop () (restart-case (error "Hop") (hop () (format t "hop")))) 

Where I define a dummy function that always fails but provides a restart: hop.

In another package, in this file:

 ;;; hip.lisp (defpackage #:hip (:use #:cl #:hop)) (in-package :hip) (defun dhip () (hop:hop)) (defun hip () (handler-case (hop:hop) (error (e) (declare (ignore e)) (format t "restarts: ~a~%" (compute-restarts)) (invoke-restart 'hop)))) 

I define a function (hip) and (dhip) that call the function (hop) from the first package.

When I call (dhip), sbcl offers me a prompt where I can choose to restart using my branch host:

 Hop [Condition of type SIMPLE-ERROR] Restarts: 0: [HOP] HOP 1: [RETRY] Retry SLIME REPL evaluation request. 2: [*ABORT] Return to SLIME top level. 3: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {1009868103}>) Backtrace: 0: (HOP) 1: (DHIP) 2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (DHIP) #<NULL-LEXENV>) 3: (EVAL (DHIP)) --more-- 

This is what I expected.

However, when I call (hip), my host restart is not specified (compute-restart), and it cannot use it: (

 No restart HOP is active. [Condition of type SB-INT:SIMPLE-CONTROL-ERROR] Restarts: 0: [RETRY] Retry SLIME REPL evaluation request. 1: [*ABORT] Return to SLIME top level. 2: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {1009868103}>) Backtrace: 0: (SB-INT:FIND-RESTART-OR-CONTROL-ERROR HOP NIL T) 1: (INVOKE-RESTART HOP) 2: ((FLET #:FUN1 :IN HIP) #<unused argument>) 3: (HIP) 4: (SB-INT:SIMPLE-EVAL-IN-LEXENV (HIP) #<NULL-LEXENV>) 5: (EVAL (HIP)) 

Do you know what you can do to do this?

Thanks,

Guillaule

+4
source share
1 answer

This has nothing to do with packages.

With HANDLER-CASE, the stack is already unwinding when the handler is running. Thus, the restart set in the function disappeared.

Use HANDLER-BIND instead. It starts the handler in the context of the error, and, therefore, function reloads are available.

Example:

 (defun hip () (handler-bind ((error (lambda (e) (declare (ignore e)) (format t "restarts: ~a~%" (compute-restarts)) (invoke-restart 'hop)))) (hop))) 
+5
source

All Articles