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

Issue: STANDARD-INPUT-INITIAL-BINDING (version 2)



Issue:         STANDARD-INPUT-INITIAL-BINDING
References:    Standard streams (pp. 327-329)
Category:      CHANGE
Edit history:  Version 1 by Pierson and Haflich 1/19/87
    	       Version 2 by Pierson 2/29/88
Status:        For Internal Discussion

This is a complete rewrite.  I hope the added complexity is worth it,
I don't see anyway to both hide the hair and do better than CLtL.

Problem description:

CLtL requires that *STANDARD-INPUT*, *STANDARD-OUTPUT*,
*ERROR-OUTPUT*, *TRACE-OUTPUT*, *QUERY-IO*, and *DEBUG-IO* are
initially bound to synonym streams to *TERMINAL-IO*.  This requirement
hampers the integration of Common Lisp with many existing and
potential operating environments.

For example, a Unix implementation is currently unable to legally
support Unix standard error output even though Common Lisp defines
*ERROR-OUTPUT* because *ERROR-OUTPUT* is required to start out bound
to the same stream as *STANDARD-OUTPUT*.  A workstation environnment
which provides stream access to windows as an extension is currently
forbidden to make trace output appear in a separate window by default
because *TRACE-OUTPUT* is required to start out bound to the same
stream as *STANDARD-OUTPUT*.

Proposal (STANDARD-INPUT-INITIAL-BINDING:DEFINED-CONTRACTS):

A Common Lisp implementation is required to provide two sets of open
streams, Primitive Streams, and User Streams.  Most user programs
should only use the User Streams; each User Stream has a specific
purpose as defined in CLtL. [[ If this proposal is accepted I can be
persuaded to retype the page and a half of definitions here.]]  The
Primitive Streams are the initial defined interfaces between Lisp and
the non-Lisp world.  The primary purpose of the Primitive Streams is
to make it possible to portably recover from a stream-binding error on
any User Stream, for this reason it is an error to rebind or set any
Primitive Stream.  Implementations are encouraged, but not required to
signal a correctable error if a Primitive Stream is rebound.

Primitive Streams:
    *INITIAL-INPUT*
    	This stream is bound to the primary default input of the Lisp
	system (e.g. standard input on Unix, SYS$INPUT on VMS).  While
	this will probably be an interactive terminal or window during
	program development, it may well be a data file for a
	non-interactive application.
    *INITIAL-OUTPUT*
    	This stream is bound to the primary default output of the Lisp
	system (e.g. standard output on Unix, SYS$OUTPUT on VMS).  While
	this will probably be an interactive terminal or window during
	program development, it may well be a data file for a
	non-interactive application.
    *INITIAL-QUERY-INPUT*
    	Whenever possible, this stream is bound to an interactive
	input source.  This may be the same as *initial-input* in a
	development environment, or it may be a separate window, or
	terminal.  If the Lisp system is running under an operating
	system such as Aegis which provides a separate error input
	source, this stream should probably be bound to that source.
	In a non-interactive environment for which no interactive input
	is available, reading this stream will always result in EOF.
    *INITIAL-ERROR-OUTPUT*
    	If *initial-query-input* is bound to an interactive input source,
	this stream should be bound to the cooresponding interactive output
	destination such that *query-io* will work in the expected way if
	bound to a two-way stream between these two streams.  If the Lisp
	system is running under an operating system such as Aegis, Unix,
	or VMS which provides a separate error output destination, this
	stream should be bound to that destination.  In a non-interactive
	environment without a separate error destination, this stream should
	be bound to the same destination as *initial-output*.

User Streams:
    *TERMINAL-IO*
    	The initial binding of *terminal-io* is a two-way stream between
	*initial-input* and *initial-output* unless these streams can be
	determined to be non-interactive and *initial-query-input* and
	*initial-error-output* can both be determined to be real interactive
	streams (e.g. reading *initial-query-input* does not always result
	in EOF), in which case *terminal-io* is bound to a two-way stream
	between them.  In a windowing environment, *terminal-io* may refer
	to a different window than *query-io* (and therefore than any of
	the *initial-foo* streams) as long as all of these streams refer
	to windows.
    *STANDARD-INPUT*
    	The initial binding of *standard-input* is *initial-input*.
    *STANDARD-OUTPUT*
    	The initial binding of *standard-output* is *initial-output*.
    *ERROR-OUTPUT*
    	The initial binding of *error-output* is *initial-error-output*.
    *TRACE-OUTPUT*
    	The initial binding of *trace-output* is  *initial-error-output*
	in a non-windowed environment.  In a windowed environment,
    	*trace-output* may start out bound in some other way (e.g. to
	a non-existant trace output window which will be automagically
	created when output is first done to *trace-output*).
    *QUERY-IO*
    	Initially bound to a two way stream between *initial-query-input*
	and *initial-error-output*.
    *DEBUG-IO*
    	The initial binding of *debug-io* is  *initial-error-output* in a
	non-windowed environment.  In a windowed environment, *debug-io*
	may start out bound in some other way.

Test Cases/Examples:

(PROGN
   (PRINT "Output" *STANDARD-OUTPUT*)
   (PRINT "Error" *STANDARD-ERROR*))

In current Common Lisp will write:
------
Output
Error
------

With proposal *might* write:
------
Output
------
and "Error" appears somewhere else.

Rationale:

This proposal attempts to provide a balance between over-specifying
behavior to the point that Lisp programs can't behave like other
programs in conventional operating systems and providing enough
specification that Common Lisp programs can perform portable input and
output including safe rebinding of the standard streams.

Current practice:

Lucid binds *TERMINAL-IO* to a special internal stream type.  Franz
binds *TERMINAL-IO* to a special internal stream type for terminal
streams which reads from Unix standard input and writes to Unix
standard output.  KCL binds *TERMINAL-IO* to a standard two-way-stream
with input from Unix standard input and output to Unix standard
output.

Cost to Implementors:

All implementations will have to change to some degree but the changes
will probably be simple and localized.  Most implementations already
include some or all of the initial streams as internal stream types so
this is largely a documentation and initialization task.

Cost to Users:

User code which depends on the strict binding hierarchy in CLtL may
have to change.  

Cost of non-Adoption:

It will continue to be difficult or impossible to integrate portable
Common Lisp progams in conventional operating system environments.
Many implementations will have to continue to choose between
conforming to the standard and providing a superior user environment.

Benefits:

Implementations will be more able to match their IO behavior to their
environment and their user's expectations.  

Aesthetics:

The four new streams appear to add complexity but they also separate
the previous intermixed concepts of initial bindings and standard
purpose streams.

Discussion:

The repeated mention of windowing environments above seems to be
getting dangerously close to the environmental issues this standard is
supposed to avoid, but Pierson feels that if we have to do more than
leave these areas undefined, we also have to give advanced
environments official permission to do their thing.