Hi,
I am writing a wrapper function to C code (still cairo ;-), where
error status needs to be queried explicitly. The following
self-contained code demonstrates what I am trying to do:
(defun query-status () 'success)
(defmacro catch-error (&body body)
(let ((result (gensym))
(status (gensym)))
`(let* ((,result (progn ,@body))
(,status (query-status)))
(if (eq ,status 'success)
,result
(warn "status is ~a" ,status)))))
Now the fly in the ointment: it works fine if body returns a single value:
(catch-error
(+ 1 1))
but not so with multiple values:
(catch-error
(floor pi))
Is there a solution to this that would work in both cases?
Thanks,
Tamas
--
Posted via a free Usenet account from http://www.teranews.com
On May 15, 2:43 pm, Tamas Papp <······@gmail.com> wrote:
> Hi,
>
> I am writing a wrapper function to C code (still cairo ;-), where
> error status needs to be queried explicitly. The following
> self-contained code demonstrates what I am trying to do:
>
> (defun query-status () 'success)
>
> (defmacro catch-error (&body body)
> (let ((result (gensym))
> (status (gensym)))
> `(let* ((,result (progn ,@body))
> (,status (query-status)))
> (if (eq ,status 'success)
> ,result
> (warn "status is ~a" ,status)))))
>
> Now the fly in the ointment: it works fine if body returns a single value:
>
> (catch-error
> (+ 1 1))
>
> but not so with multiple values:
>
> (catch-error
> (floor pi))
>
> Is there a solution to this that would work in both cases?
(defmacro catch-error (&body body)
(let ((result (gensym))
(status (gensym)))
`(let* ((,result (multiple-value-list (progn ,@body)))
(,status (query-status)))
(if (eq ,status 'success)
(apply #'values ,result)
(warn "status is ~a" ,status)))))
---
Geoff
On May 15, 2:43 pm, Tamas Papp <······@gmail.com> wrote:
> Hi,
>
> I am writing a wrapper function to C code (still cairo ;-), where
> error status needs to be queried explicitly. The following
> self-contained code demonstrates what I am trying to do:
>
> (defun query-status () 'success)
>
> (defmacro catch-error (&body body)
> (let ((result (gensym))
> (status (gensym)))
> `(let* ((,result (progn ,@body))
> (,status (query-status)))
> (if (eq ,status 'success)
> ,result
> (warn "status is ~a" ,status)))))
>
> Now the fly in the ointment: it works fine if body returns a single value:
>
> (catch-error
> (+ 1 1))
>
> but not so with multiple values:
>
> (catch-error
> (floor pi))
>
> Is there a solution to this that would work in both cases?
(defmacro catch-error (&body body)
(let ((result (gensym))
(status (gensym)))
`(let* ((,result (multiple-value-list (progn ,@body)))
(,status (query-status)))
(if (eq ,status 'success)
(apply #'values ,result)
(warn "status is ~a" ,status)))))
---
Geoff
On May 15, 11:43 am, Tamas Papp <······@gmail.com> wrote:
> Hi,
>
> I am writing a wrapper function to C code (still cairo ;-), where
> error status needs to be queried explicitly. The following
> self-contained code demonstrates what I am trying to do:
>
> (defun query-status () 'success)
>
> (defmacro catch-error (&body body)
> (let ((result (gensym))
> (status (gensym)))
> `(let* ((,result (progn ,@body))
> (,status (query-status)))
> (if (eq ,status 'success)
> ,result
> (warn "status is ~a" ,status)))))
>
> Now the fly in the ointment: it works fine if body returns a single value:
The easiest way to fix this is to capture the multiple values out of
the BODY as a list using MULTIPLE-VALUE-LIST. The list is then be
converted back to multiple values using VALUES-LIST.
On May 15, 11:43 am, Tamas Papp <······@gmail.com> wrote:
> Hi,
>
> I am writing a wrapper function to C code (still cairo ;-), where
> error status needs to be queried explicitly. The following
> self-contained code demonstrates what I am trying to do:
>
> (defun query-status () 'success)
>
> (defmacro catch-error (&body body)
> (let ((result (gensym))
> (status (gensym)))
> `(let* ((,result (progn ,@body))
> (,status (query-status)))
> (if (eq ,status 'success)
> ,result
> (warn "status is ~a" ,status)))))
>
> Now the fly in the ointment: it works fine if body returns a single value:
>
> (catch-error
> (+ 1 1))
>
> but not so with multiple values:
>
> (catch-error
> (floor pi))
>
> Is there a solution to this that would work in both cases?
if you know the number of values returned you can use MULTIPLE-VALUE-
BIND, otherwise you can use MULTIPLE-VALUES-LIST
(defmacro catch-error (&body body)
(let ((result (gensym))
(status (gensym)))
`(let* ((,result (multiple-value-list (progn ,@body)))
(,status (query-status)))
(if (eq ,status 'success)
(apply #'values ,result)
(warn "status is ~a" ,status)))))
········@gmail.com writes:
> On May 15, 11:43 am, Tamas Papp <······@gmail.com> wrote:
> > Hi,
> >
> > I am writing a wrapper function to C code (still cairo ;-), where
> > error status needs to be queried explicitly. The following
> > self-contained code demonstrates what I am trying to do:
> >
> > (defun query-status () 'success)
> >
> > (defmacro catch-error (&body body)
> > (let ((result (gensym))
> > (status (gensym)))
> > `(let* ((,result (progn ,@body))
> > (,status (query-status)))
> > (if (eq ,status 'success)
> > ,result
> > (warn "status is ~a" ,status)))))
...
> if you know the number of values returned you can use MULTIPLE-VALUE-
> BIND, otherwise you can use MULTIPLE-VALUES-LIST
>
> (defmacro catch-error (&body body)
> (let ((result (gensym))
> (status (gensym)))
> `(let* ((,result (multiple-value-list (progn ,@body)))
> (,status (query-status)))
> (if (eq ,status 'success)
> (apply #'values ,result)
> (warn "status is ~a" ,status)))))
First, do you really just want the result of the call to WARN (that
is, NIL) to be re returned in the warning case? It's usually clearer
to do that explicitly rather than just assume that an operator will
return the right thing.
Second, I'm not sure I see where the "catching" is going on. I think you
should not call this macro catch-xxx unless it catches something. If
instead what it is just passively review error status of normally
returning things and not catch other things, then maybe another name?
NOTICING-UNSUCCESSFUL-RESULT or WARNING-UPON-SUSPICIOUS-RETURN or some
such thing would work better for me. Don't use a name with a meaning
already associated with it unless you mean to attach that meaning.
Third, just for grins, I want to point out that there are sometimes
alternatives to multiple-value-list. I've incorporated one of them here...
(defmacro warning-upon-suspicious-return (&body body)
(let ((bypass (gensym)))
`(block ,bypass
(multiple-value-prog1 (progn ,@body)
(unless (eq (query-status) 'success)
(warn "status is ~A" ,status)
(return-from ,bypass nil))))))
Or else perhaps you want to return the warning...
(defmacro warning-upon-suspicious-return (&body body)
(let ((bypass (gensym "BYPASS")) (status (gensym "STATUS")))
`(block ,bypass
(multiple-value-prog1 (progn ,@body)
(let ((,status (query-status)))
(unless (eq ,status 'success)
(return-from ,bypass (warn-about-suspicious-return ,status))))))))
(defun warn-about-suspicious-return (status)
(let ((warning (make-instance 'simple-warning
:format-control "status is ~A"
:format-arguments (list status))))
(warn warning)
warning))
I didn't test this code, so there might be errors, but hopefully you get
the point.
Tamas Papp <······@gmail.com> writes:
> Hi,
>
> I am writing a wrapper function to C code (still cairo ;-), where
> error status needs to be queried explicitly. The following
> self-contained code demonstrates what I am trying to do:
>
> (defun query-status () 'success)
>
> (defmacro catch-error (&body body)
> (let ((result (gensym))
> (status (gensym)))
> `(let* ((,result (progn ,@body))
> (,status (query-status)))
> (if (eq ,status 'success)
> ,result
> (warn "status is ~a" ,status)))))
>
> Now the fly in the ointment: it works fine if body returns a single value:
>
> (catch-error
> (+ 1 1))
>
> but not so with multiple values:
>
> (catch-error
> (floor pi))
>
> Is there a solution to this that would work in both cases?
(defmacro catch-error (&body body)
(let ((vstatus (gensym)))
`(multiple-value-prog1 (progn ,@body)
(let ((,vstatus (query-status)))
(unless (eq ,vstatus 'success)
(warn "status is ~A" ,vstatus))))))
C/USER[21]> (let ((s t)) (defun query-status () (or (setf s (not s)) 'success)))
QUERY-STATUS
C/USER[22]> (catch-error (values 1 2 3))
1 ;
2 ;
3
C/USER[23]> (catch-error (values 1 2 3))
WARNING: status is T
1 ;
2 ;
3
--
__Pascal Bourguignon__ http://www.informatimago.com/
NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
Pascal Bourguignon <···@informatimago.com> writes:
> (defmacro catch-error (&body body)
> (let ((vstatus (gensym)))
> `(multiple-value-prog1 (progn ,@body)
> (let ((,vstatus (query-status)))
> (unless (eq ,vstatus 'success)
> (warn "status is ~A" ,vstatus))))))
Wow--deja vu.. I had to look twice to make sure I wasn't re-reading
the message I just sent. I guess I should have waited before
replying! (But I'm always afraid I won't be able to find the messages
again that I want to respond to, so I usually just jot something down
while I'm there.)