[comp.lang.icon] overcoming inelegance

nowlin@iwtqg.att.com (01/18/91)

> Subject: Overcoming inelegance?
>  
> Many times I've encountered the following problem: I have a procedure *p*
> that each time it's called writes some material to a file *f*.  I want to
> pass *f* as a command-line parameter and close *f* when I'm done.  There
> are two inelegant ways to do this:
> 
> (1) Make the file name a global variable; open and close it outside of *p*.
> 
> (2) Jigger the parameters passed to *p* so that a special form of argument
> indicates file opening or closing rather than data to be written.
> 
> Is there an elegant way?  (A similar problem exists for input.)
> 
> Paul Abrahams
> abrahams%wayne-mts@um.cc.umich.edu

A compromise to the global variable is to pass an opened file pointer into
the procedure p().  Just open the file outside the procedure and close it
after the last time the procedure is called.  The ability to have the
entire open(), write(), close() suite of calls contained in the procedure
is tricky.  The procedure then has to know the file name somehow.

The real problem I see with the self-contained approach is the same one
that was batted around when the discussion of a "final" clause was going
on.  How do you know when it's the last time you're calling a procedure?
In this special case you should be able to rely on the language itself or
the underlying operating system to flush all buffers and close all opened
files as a program terminates.  Then you only need to worry about opening
the file.  Is the following the kind of idea you had?  The comment explains
the concept:

procedure main(args)
	p("first output")
	every f := !args do every p(1 to 10,f)
	p("last output")
end

# This procedure writes the data 'd' to an output stream.  'f' is optional
# but if passed it's assumed to be a file name and is checked against the
# currently open file.  If they're the same continue writing to the open
# file.  If they're different close the current file and open the new one. 
# If no file is ever passed all writing is to standard output.  NOTE: It is
# assumed that the system itself will flush and close the final file opened.

procedure p(d,f)

	static	o
	initial	o := &null

	if \f & not (image(o) ? (="file(" & f == tab(upto(')')))) then {
		if image(o) ? ="file(" then close(o)
		o := open(f,"w") | stop("can't open: ",f)
	}

	write(o,d)

	return
end

Realize, I don't like the idea of relying on the system to close files for
me.  That's sloppy not elegant.  Maybe someone will come up with a better
idea.

Jerry Nowlin
att!iwtqg!nowlin