I'm trying to use conditions to solve a dilemma I have in a macro, and
am hoping a for a little help on what is "typical" and good practice
when using them.
Problem:
I have a program that requires a significant amount of initialization
that must also be de-init'ed when done. I've devised a nice WITH style
macro that handles all this for me. Example..
(defmacro with-stuff (&body body)
`(when (test)
(handler-case
(progn
,@(lots-of-init-functions)
,@body)
(condition () nil))
(de-init)))
This works out quite nicely, because if anything during the init phase
or body were to fail, the de-init code is still executed and everything
is cleaned up for the next attempt.
However, the downside, of course, is that I can't get debugging
information about the error (sure, I can return the condition, but I
can't backtrace, etc). Am I missing something simple about conditions
or a function perhaps that will help me out?
Simply put, I'd like my cake and to eat it, too. I want all the
debugging abilities, but I'd also like the clean-up code to execute so
I don't have to do it myself in the REPL. Much like a finally
statement. Open to suggestions, and thanks, as always ;)
Jeff M.
--
(a (href "http://www.retrobyte.org/"))
(a (href ···············@gmail.com"))
Jeff wrote:
> I'm trying to use conditions to solve a dilemma I have in a macro, and
> am hoping a for a little help on what is "typical" and good practice
> when using them.
>
> Problem:
>
> I have a program that requires a significant amount of initialization
> that must also be de-init'ed when done. I've devised a nice WITH style
> macro that handles all this for me. Example..
>
> (defmacro with-stuff (&body body)
> `(when (test)
> (handler-case
> (progn
> ,@(lots-of-init-functions)
> ,@body)
> (condition () nil))
> (de-init)))
>
> This works out quite nicely, because if anything during the init phase
> or body were to fail, the de-init code is still executed and everything
> is cleaned up for the next attempt.
>
> However, the downside, of course, is that I can't get debugging
> information about the error (sure, I can return the condition, but I
> can't backtrace, etc). Am I missing something simple about conditions
> or a function perhaps that will help me out?
If you use handler-bind the stack is not unwound. You can get the debugger
and thus the backtrace (or do your own restarts). In the example
below the debugger is invoked on a condition. The unwind-protect will
allow the de-init function to be called even if you abort in the debugger.
when you want conditions to invoke-debugger.
(defmacro with-stuff (&body body)
`(when (test)
(unwind-protect
(handler-bind
(condition #'invoke-debugger)
,@(lots-of-init-functions)
,@body)
(de-init))))
Wade
"Jeff" <·······@gmail.com> writes:
> [...]
> (handler-case
> [...]
> This works out quite nicely, because if anything during the init phase
> or body were to fail, the de-init code is still executed and everything
> is cleaned up for the next attempt.
>
> However, the downside, of course, is that I can't get debugging
> information about the error (sure, I can return the condition, but I
> can't backtrace, etc). Am I missing something simple about conditions
> or a function perhaps that will help me out?
UNWIND-PROTECT
--
__Pascal Bourguignon__ http://www.informatimago.com/
The world will now reboot; don't bother saving your artefacts.
"Jeff" <·······@gmail.com> writes:
> Problem:
>
> I have a program that requires a significant amount of initialization
> that must also be de-init'ed when done. I've devised a nice WITH style
> macro that handles all this for me. Example..
>
> (defmacro with-stuff (&body body)
> `(when (test)
> (handler-case
> (progn
> ,@(lots-of-init-functions)
> ,@body)
> (condition () nil))
> (de-init)))
>
> This works out quite nicely, because if anything during the init phase
> or body were to fail, the de-init code is still executed and everything
> is cleaned up for the next attempt.
If I understand what you are trying to do correctly, then you want
something like this:
(defmacro with-stuff (&body body)
`(when (test)
(unwind-protect
(progn ,@(lots-of-init-functions)
,@body)
(de-init))))
What this does is run the DE-INIT form when the stack unwinds, whether
because the protected form has finished executing, or because an error
has been raised.
However, you could achieve a similar effect (less robustly), with:
(defmacro with-stuff (&body body)
`(when (test)
(handler-case (progn ,@(lots-of-init-functions)
,@body)
(serious-condition (condition)
(de-init)
(error condition)))
(de-init)))
Cheers,
Iain
Iain Little wrote:
> If I understand what you are trying to do correctly, then you want
> something like this:
>
> (defmacro with-stuff (&body body)
> `(when (test)
> (unwind-protect
> (progn ,@(lots-of-init-functions)
> ,@body)
> (de-init))))
>
> What this does is run the DE-INIT form when the stack unwinds, whether
> because the protected form has finished executing, or because an error
> has been raised.
Absolutely beautiful! Worked like a charm. Thank you very much!
Jeff M.
--
(a (href "http://www.retrobyte.org/"))
(a (href ···············@gmail.com"))