From: David M. Ely
Subject: question about sending output to files
Date: 
Message-ID: <330692EA.167E@cs.utexas.edu>
Is there a way to open a file in one function and have it be accessible
to other functions that it calls?  I know you can use:

(with-open-file (filename "output" :direction :output)
                (format filename "hello"))

to write to a file.  But if I try something like:

(defun driver (x)
	(with-open-file (filename "output" :direction :output)
		(doprint (x))))


(defun doprint (x)
	(format filename "X is ~a" x))


entering (doprint '(a)) give me "The variable FILENAME is unbound".  

Any suggestions would be greatly appreciated.

Thanks

David Ely
From: Donald H. Mitchell
Subject: Re: question about sending output to files
Date: 
Message-ID: <330CE8D7.890@pgh.net>
Marco Antoniotti wrote:
> 
> "David M. Ely" <···@cs.utexas.edu> writes:
> 
> >
> > Is there a way to open a file in one function and have it be accessible
> > to other functions that it calls?  I know you can use:
> >
> > (with-open-file (filename "output" :direction :output)
> >                 (format filename "hello"))

You already know what to do.  format is merely a function.  You are 
passing the file to format.  Just pass it to whatever other functions you 
would like to pass it to.

> > (defun driver (x)
> >       (with-open-file (filename "output" :direction :output)
> >               (doprint (x))))

       (doprint x filename))))

> > (defun doprint (x)
> >       (format filename "X is ~a" x))

(defun doprint (thing sream)
   (format stream "X is ~A" thing))


> > entering (doprint '(a)) give me "The variable FILENAME is unbound".

CL is lexically-scoped which intuitively means that code can only access 
the variables that are defined in the same place; thus, the compiler can 
forget all about variable names as soon as it's done with each section of 
code where a section is no bigger than a defun.  Said another way, only 
variables defined in the same "paragraph".  This way, when you write one 
function, you don't have to know what names you've already used for 
variables in other places.

> (defun driver (x)
>    (let ((file-stream (open "output" :direction :output
>                                      :if-does-not-exist :create
>                                      :if-exists :supersede)))
>      (doprint x file-stream)
>      (close file-stream))

Making a mountain out of a molehill and taking a simple example to task, 
note that this example is very dangerous in that it doesn't guarantee 
that file-stream will get closed.  If doprint gets an error, calls throw 
or invoke-restart, or in any other way causes the function to abort, the 
stream will not be closed. The more correct formulation would be

(defun driver (x)
   (let ((file-stream (open "output" ...)))
     (unwind-protect   ; the magical protector against all aborts
       (doprint x file-stream)
       (close file-stream))))

-- 
Donald H. Mitchell              ···@pgh.net
Proactive Solutions, Inc.       412.835.2410
5858 Horseshoe Dr.              412.835.2411 (fax)
Bethel Park, PA 15102