[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

I/O proposal



>From Gary Brooks and William Clinger at Indiana U:

This is an interim proposal.  It takes an old-fashioned view of
streams, and it does nothing about windows and graphics.  Arguments to 
functions are delimited by angle brackets (<...>) and optional arguments
are further delmited by curly brackets ({...}).



(eof? <object>)                                         Essential

   EOF? takes an object and returns true if the object is an end of
   file object.  The precise set of end of file objects will vary
   among implementations, but in any case no end of file object will
   ever be a character or an object that can be read in using READ.

   Rationale:
   A fixed set of end of file objects seems to be simpler than
   allowing each input procedure to take yet another optional
   argument specifying what to do on end of file.  Allowing for a
   set of such objects rather than a single such object allows for
   different implementation strategies.


(read {<stream>})                                               Essential

   READ takes an input stream as argument and returns the next
   object parsable from the stream, updating the stream to point to
   the first character past the end of the written representation of
   the object.  If an end of file is encountered in the input before
   any characters are found that can begin an object, then an end of
   file object is returned.  If an end of file is encountered after
   the beginning of an object's written representation, but the
   written representation is incomplete and therefore not parsable,
   an error must be signalled.  The stream argument to READ may be
   omitted, in which case it defaults to (CURRENT-INPUT-STREAM).

   Rationale:
   READ corresponds to Common Lisp's READ-PRESERVING-WHITESPACE.
   This will require something like UNREAD-CHAR or PEEK-CHAR
   internally.  For simplicity, it is never an error to encounter
   end of file when READ is called.


(write <object> {<stream>})                             Essential

   WRITE takes an object and an output stream and writes a
   representation of the object to the stream.  Strings that appear
   in the written representation are enclosed in double quotes, and
   within those strings backslash and double quote characters are
   escaped by backslashes.  (Implementations that allow
   slashification within symbols will probably want WRITE to
   slashify funny characters in symbols as well.)  WRITE returns an
   unspecified value. The stream argument to WRITE may be omitted,
   in which case it defaults to (CURRENT-OUTPUT-STREAM).


(display <object> {<stream>})                           Essential

   DISPLAY takes an object and an output stream and writes a
   representation of the object to the stream.  Strings that appear
   in the written representation are not enclosed in double quotes,
   and no characters are escaped within those strings.  DISPLAY
   returns an unspecified value.  The stream argument to DISPLAY may
   be omitted, in which case it defaults to (CURRENT-OUTPUT-STREAM).
   
   Rationale:
   WRITE is for producing machine-readable output, DISPLAY for
   producing human-readable output.
   
(newline {<stream>})                                    Essential

   NEWLINE takes an output stream and writes a newline to the
   stream.  NEWLINE returns an unspecified value.  The stream
   argument to NEWLINE may be omitted, in which case it defaults to
   (CURRENT-OUTPUT-STREAM).
   
   Rationale:
   NEWLINE abstracts away from the implementation details of
   ending a line (or is it starting a new one?).

(listen? {<stream>})                                    Optional

   LISTEN? takes an input stream (an interactive stream in the
   useful case) and returns true if a character is ready on that
   stream so that a READ-CHAR operation will not hang and returns
   false if a READ-CHAR operation will hang.  If the stream is at
   end of file then the value returned by LISTEN? is unspecified.
   
   Rationale:
   LISTEN? is needed for interactive input streams.

(read-char {<stream>})                                  Essential

   READ-CHAR takes an input stream and returns the next character
   available from the stream, updating the stream to point to the
   following character.  If no more characters are available from
   the stream, an end of file value is returned.  The stream
   argument to READ-CHAR may be omitted, in which case it defaults
   to (CURRENT-INPUT-STREAM).
   
(display-char <character> {<stream>})                   Essential

   DISPLAY-CHAR takes a character and an output stream, and writes
   the character itself (not a written representation of the
   character) to the stream.  DISPLAY-CHAR returns an unspecified
   value. The stream argument to DISPLAY-CHAR may be omitted, in
   which case it defaults to (CURRENT-OUTPUT-STREAM).
   
   Rationale:   
   READ-CHAR and DISPLAY-CHAR are for low-level I/O.

(load <filename>)                                       Essential

   LOAD takes a string that names an existing file containing Scheme
   source code.  It reads Scheme expressions from the file and
   interprets them sequentially as though they had been typed
   interactively.  It is not specified whether the results of the
   expressions are printed.  Neither is it specified whether or not the
   LOAD procedure affects the values returned by (CURRENT-INPUT-STREAM)
   and (CURRENT-OUTPUT-STREAM) during the loading process.  LOAD returns
   an unspecified value.
   
   Rationale:
   For portability LOAD must operate on source files.  Its operation
   on other kinds of files necessarily varies among implementations.
   
(transcript-on <file-name>)                             Optional

   TRANSCRIPT-ON takes a string that names an output file to be
   created, and returns an unspecified value.  The effect of
   TRANSCRIPT-ON is to open the named file for output, and to cause
   a transcript of subsequent interaction between the user and the
   Scheme system to be written to the file.  The transcript is ended
   by a call to TRANSCRIPT-OFF.  Only one transcript may be in
   progress at any time.  (Some implementations may relax this
   restriction.)

(transcript-off)                                        Optional

   TRANSCRIPT-OFF takes no arguments and returns an unspecified
   value.  It ends any transcript in progress and closes the
   transcript file.
   
   Rationale:
   TRANSCRIPT-ON and TRANSCRIPT-OFF are redundant in some systems,
   but systems that need them should provide them.

(stream? <object>)                                      Essential

   STREAM? takes one argument and returns true iff its argument is a
   stream.
   
   Rationale:
   Perhaps STREAM? should be subdivided into INPUT-STREAM? and
   OUTPUT-STREAM?.

(current-input-stream)                                  Essential

   CURRENT-INPUT-STREAM takes no arguments and returns the current
   default input stream.

(current-output-stream)                                 Essential

   CURRENT-OUTPUT-STREAM takes no arguments and returns the current
   default output stream.
   
   Rationale:
   CURRENT-INPUT-STREAM and CURRENT-OUTPUT-STREAM are procedures
   rather than variables to allow for various ways to implement the
   default streams.  Explicit fetching of the default streams is
   convenient for programs that want to change the default stream
   using WITH-INPUT-FROM-FILE or WITH-OUTPUT-TO-FILE and still use
   the original default stream for some I/O; see below.
   
(call-with-input-file <string> <procedure>)             Essential

   CALL-WITH-INPUT-FILE takes a procedure of one argument and a 
   string naming an existing file and calls the procedure with the
   stream obtained by opening the named file for input.  If the
   file cannot be opened, an error should be signalled. If the
   procedure returns, then the stream is closed automatically and
   the value yielded by the procedure is returned by
   CALL-WITH-INPUT-FILE. If the current continuation ever changes in
   such a way as to make it doubtful that the procedure will return,
   CALL-WITH-INPUT-FILE may close the input stream.  The exact
   interaction of escape procedures with CALL-WITH-INPUT-FILE is
   unspecified.
   
(call-with-output-file <file-name> <procedure>)         Essential

   CALL-WITH-OUTPUT-FILE takes a procedure of one argument and a string
   naming a file to be created and calls the procedure with the stream
   obtained by opening the named file for output.  If the file cannot be
   be opened, an error should be signalled. If a file with that name
   already exists, the effect is unspecified. If the procedure returns,
   then the stream is closed automatically and the value yielded by the
   procedure is returned by CALL-WITH-OUTPUT-FILE. If the current
   continuation ever changes in such a way as to make it doubtful that
   the procedure will return, CALL-WITH-OUTPUT-FILE may close the output
   stream.  The exact interaction of escape procedures with
   CALL-WITH-OUTPUT-FILE is unspecified.  

   Rationale:
   CALL-WITH-INPUT-FILE and CALL-WITH-OUTPUT-FILE are convenient for
   programs that need to read input from or send output to several
   directions at once. They cannot be synthesized from
   WITH-INPUT-FROM-FILE and WITH-OUTPUT-TO-FILE so they are the essential
   procedures.  Whether or not they close files when there is a throw out
   of the procedure is mainly a performance issue, of greatest importance
   when there is a small limit on the number of files that can be open at
   once.  If they close files for a throw, then the vagueness of what it
   means for the current continuation to change in such a way as to make
   it doubtful that a procedure will return, the possibility of a throw
   back in, and the vagueness of what it means to close a file, make it
   unwise to specify the exact interaction of the file-closing mechanism
   with escape procedures.

   It is arguable whether the notion of closing a file should be
   reflected in the semantics of Scheme.  Operating systems require
   that files be closed for the following reasons:
   
       1.  To reclaim storage.  This should be left to the garbage
       collector.
   
       2.  To prevent some table in the operating system from
       overflowing because there are too many files open at once.
       Only implementations that have this problem should have to
       worry about it.
   
       3.  To facilitate file locking.  This seems to be the only
       semantic reason for closing a file, and even so there are
       implementations for which it isn't meaningful.
   
   Because some systems have to worry about closing files, however,
   all portable Scheme code must worry about it.  We have tried to
   follow MIT's lead in isolating the worry within a few standard
   procedures.
   
   
(open-input-file <file-name>)                           Optional

   OPEN-INPUT-FILE takes a string naming an existing file and
   returns an input stream capable of delivering characters from the
   file.  If the file cannot be opened, an error should be signalled.

(open-output-file <file-name>)                          Optional

   OPEN-OUTPUT-FILE takes a string naming an output file to be
   created and returns an output stream capable of writing
   characters to a new file by that name.  If the file cannot be
   opened, an error should be signalled.  If a file with the given
   name already exists, the effect is unspecified.
   
(close-input-stream <stream>)                           Optional

   CLOSE-INPUT-STREAM takes an input stream and returns an
   unspecified value.  If the stream is connected to a file, the
   file is closed and the stream rendered incapable of delivering
   characters.

(close-output-stream <stream>)                          Optional

   CLOSE-OUTPUT-STREAM takes an output stream and returns an
   unspecified value.  If the stream is connected to a file, the
   file is closed and the stream rendered incapable of writing
   characters to it.

   Rationale:
   OPEN-INPUT-FILE, OPEN-OUTPUT-FILE, CLOSE-INPUT-STREAM, and
   CLOSE-OUTPUT-STREAM are needed to use streams whose lifetimes are
   not properly nested, which is to say they are seldom needed.
   OPEN-INPUT-FILE and OPEN-OUTPUT-FILE are distinct to avoid the
   need for a switch argument; if independent switches were
   required, it would be better to use switches rather than have a
   product space of procedures.  CLOSE-INPUT-STREAM and
   CLOSE-OUTPUT-STREAM could probably be combined into CLOSE-STREAM
   with no great loss.  A different set of procedures will
   be needed to create streams from and to strings, and the closing
   procedures should still work on them.  It seems that closing a
   string output stream should yield a string, but it isn't clear
   what should be returned when a file output stream is closed.

(with-input-from-file <file-name> <thunk>)              Optional

   WITH-INPUT-FROM-FILE takes a string and a thunk (a procedure of
   no arguments).  The string must name an existing file.  The file
   is opened for input, an input stream connected to it is made the
   default value returned by (CURRENT-INPUT-STREAM), and the thunk
   is invoked.  When the thunk returns, (CURRENT-INPUT-STREAM) is
   closed and the previous default value returned by
   (CURRENT-INPUT-STREAM) is restored. WITH-INPUT-FROM-FILE returns
   the value returned by the thunk. Furthermore WITH-INPUT-FROM-FILE
   should attempt to close the input stream and restore the default
   input stream whenever the current continuation changes in such a
   way as to make it doubtful that the thunk will ever return.

(with-output-to-file <file-name> <thunk>)               Optional

   WITH-OUTPUT-TO-FILE takes a stfung and a thunk.  The string names
   an output file to be created.  The file is opened for output, an
   output stream connected to it is made the default value returned
   by (CURRENT-OUTPUT-STREAM), and the thunk is invoked.  When the
   thunk returns, (CURRENT-OUTPUT-STREAM) is closed and the previous
   default value returned by (CURRENT-OUTPUT-STREAM) is restored.
   WITH-OUTPUT-FROM-FILE returns the value returned by the thunk.
   Furthermore WITH-OUTPUT-FROM-FILE should attempt to close the
   output stream and restore the default output stream whenever the
   current continuation changes in such a way as to make it doubtful
   that the thunk will ever return.
   
   It has been suggested that if evaluation of the thunk is
   abandoned and later continued then the file should be re-opened
   in exactly the same state that it had been in when it was last
   closed, but this may be awkward or inefficient in some
   implementations.
   
   Rationale:
   WITH-INPUT-FROM-FILE and WITH-OUTPUT-TO-FILE are sufficient for
   programs that only use one input or one output at a time.  Indeed
   by nesting them and by fetching the various nested streams using
   CURRENT-INPUT-STREAM and CURRENT-OUTPUT-STREAM, arbitrarily many
   input or output files may be used.  The automatic closing of the
   streams may not be terribly important in some implementations,
   but the fact that the old defaults are restored is important
   semantically.  There are several incompatible ways that they
   could interact with escape procedures, however, and at this time
   it isn't entirely clear which ways are best.  See rationale for
   CALL-WITH-OUTPUT-FILE and CALL-WITH-INPUT-FILE.