I came across a case this evening where a bunch of output was being
generated that I didn't care for, so I wrote this macro. Any idioms
that I should be aware of, or is there a more concise way?
(defmacro no-output (&body body)
"prevent the body from generating output to standard-output or error-output"
(let ((out (gensym))
(old-stdout (gensym))
(old-error (gensym)))
`(let ((,out (make-string-output-stream))
(,old-stdout *standard-output*)
(,old-error *error-output*))
(setq *standard-output* ,out)
(setq *error-output* ,out)
(unwind-protect
,@body
(setq *standard-output* ,old-stdout)
(setq *error-output* ,old-error)))))
Thanks.
--
eblood
······@newsguy.com (E. Blood) writes:
> I came across a case this evening where a bunch of output was being
> generated that I didn't care for, so I wrote this macro. Any idioms
> that I should be aware of, or is there a more concise way?
First, as *STANDARD-OUTPUT* and *ERROR-OUTPUT* are special
variables, you can just bind them with LET instead of explicitly
saving and restoring their values.
Then, you construct an output string stream that collects
characters printed by the body, but you never use the resulting
string. This seems like a waste. You could instead make a
broadcast stream with no component streams; such a stream
discards everything output to it.
(defmacro no-output (&body body)
"prevent the body from generating output to standard-output or error-output"
`(let* ((*standard-output* (make-broadcast-stream))
(*error-output* *standard-output*))
,@body))
Perhaps this should also wrap the body in a LOCALLY form,
so that declarations in it cannot affect the bindings of
*STANDARD-OUTPUT* and *ERROR-OUTPUT*. This does not matter with
standard declarations but may make a difference with extensions.
Kalle Olavi Niemitalo <···@iki.fi> writes:
> ······@newsguy.com (E. Blood) writes:
>
> > I came across a case this evening where a bunch of output was being
> > generated that I didn't care for, so I wrote this macro. Any idioms
> > that I should be aware of, or is there a more concise way?
>
> First, as *STANDARD-OUTPUT* and *ERROR-OUTPUT* are special variables,
> you can just bind them with LET instead of explicitly saving and
> restoring their values.
The following comments are an elaboration on Kalle's comments, not
contradicting them...
Well, and importantly, fake-binding them with UNWIND-PROTECT means that you
are affecting all processes globally. It means that if process A runs
this macro and assigns standard and error output and then, before it
returns, process B does likewise, then process A will be surprised by
process B in a surprising way (not to mention processes C, D, etc. that
have not run the macro at all still being surprised by A's and B's actions).
Now, in some (perhaps most) implementations, *standard-output* and
*error-output* are probably bound by most processes that are associated
with a terminal, so the effect of this may be hard to see. That's an
issue that's beyond the scope of CL's definition, since CL doesn't take
a position on either multiprocessing or windowing. But there may still,
even in those systems, be a small number of special processes in which
these variables are not bound, and executing your code in those processes
may still have the bad effect. And, surely, other variables besides
this that are not bound-per-process by the system will have the effects
I'm describing.
In general, do not ever use the unwind-protect trick to bind what you hope
is a per-process variable. Special variables are the right way to contain
a variable value change to a process.
On 09 Mar 2003 00:09:34 -0700, E Blood wrote:
> I came across a case this evening where a bunch of output was being
> generated that I didn't care for, so I wrote this macro. Any idioms
> that I should be aware of, or is there a more concise way?
Yes and yes.
> (defmacro no-output (&body body)
> "prevent the body from generating output to standard-output or error-output"
> (let ((out (gensym))
> (old-stdout (gensym))
> (old-error (gensym)))
> `(let ((,out (make-string-output-stream))
> (,old-stdout *standard-output*)
> (,old-error *error-output*))
> (setq *standard-output* ,out)
> (setq *error-output* ,out)
> (unwind-protect
> ,@body
> (setq *standard-output* ,old-stdout)
> (setq *error-output* ,old-error)))))
Try this instead:
(let* ((*standard-output* (make-broadcast-stream))
(*error-output* *standard-output*))
your-code-here)
[I wouldn't bother making it a macro]
--
Qui beneficium dedit, taceat; narret qui accepit -- Seneca
(setq reply-to
(concatenate 'string "Paul Foley " "<mycroft" '(··@) "actrix.gen.nz>"))