From: E. Blood
Subject: comments on no-output macro
Date: 
Message-ID: <86smtxqamp.fsf@blah.winkywooster.org>
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

From: Kalle Olavi Niemitalo
Subject: Re: comments on no-output macro
Date: 
Message-ID: <878yvp0xul.fsf@Astalo.kon.iki.fi>
······@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.
From: Kent M Pitman
Subject: Re: comments on no-output macro
Date: 
Message-ID: <sfwn0k4cyzk.fsf@shell01.TheWorld.com>
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.
From: Paul Foley
Subject: Re: comments on no-output macro
Date: 
Message-ID: <m2y93ou8zm.fsf@mycroft.actrix.gen.nz>
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>"))