Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HANDLER-CASE alternative which is not a macro

Tags:

common-lisp

So consider the following code:

(define-condition some-condition (error) nil)

(defmethod print-object ((obj some-condition) stream)
  (format stream "HELLO THERE"))

(defmacro error-report-test-aux (fn-to-cause-error error-type-to-catch fn-to-handle-error expected-message)
  `(let ((result-message
           (handler-case (funcall ,fn-to-cause-error)
             (,error-type-to-catch (e) (funcall ,fn-to-handle-error e)))))
     (assert (string= result-message
                      ,expected-message))
     t))

I can use it like so:

(error-report-test-aux (lambda () (error 'some-condition)) 
                       some-condition 
                       #'princ-to-string 
                       "HELLO THERE")

But I wanted to make error-report-test-aux a function instead of macro, so that i can pass to it a type of condition within a variable.

To simply write defun instead of defmacro and remove backquote and commas doesn't work because handler-case is macro and it doesn't evaluate error-type-to-catch.

My question is: Is there something like handler-case that would evaluate it's arguments (specifically condition type argument)?

like image 728
Danylo Fedorov Avatar asked Sep 17 '26 03:09

Danylo Fedorov


1 Answers

Yes and no :-)

No to your exact question

There is no standard function that would do what you want because catching errors requires establishing bindings and one usually want to bind constant symbols (like in let/let*) because it is easier to optimize.

You might consider creating a "universal" handler using handler-bind and then declining to handle "uninteresting" conditions (as suggested by @jkiiski in comments), but I am not sure if that fits your exact requirements (untested!):

(defun error-report-test-aux (fn-to-cause-error error-type-to-catch expected-message)
  (catch 'trap
    (handler-bind ((error
                    (lambda (condition)
                      (when (typep condition error-type-to-catch)
                        (throw 'trap (string= (princ-to-string condition)
                                              expected-message))))))
      (funcall fn-to-cause-error))))

Yes, implementation-specific

IF your implementation implements handler-case/handler-bind by binding an internal global variable, you can use progv to bind it yourself and thus implement your error-report-test-aux as a function.

This is probably not the best idea (your code becomes wedded to a specific implementation).

Yes, kinda

You can use the fact that some-condition names a CLOS class and use generic functions instead of the macro.

like image 80
sds Avatar answered Sep 18 '26 18:09

sds



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!