[streams-standard-discuss] Welcome to streams-standard-discuss

David Lichteblau david at lichteblau.com
Thu Sep 16 22:41:34 UTC 2004

Quoting Rudi Schlatte (rudi at constantly.at):
| Add a class 'device-stream' which is a subclass of stream of metaclass
| standard-class.  An instance of a subclass of device-stream is meant
| to manage an "underlying device", e.g. a file or socket.

OK, so there will be at least two objects for each Common Lisp streams,
the stream itself and the device beneath it.  That is nice because it
allows applications to call device layer functions directly without
creating a full streams first and then "bypassing" the upper layers.

OTOH, I am unclear about how the device and the buffering layer would
interact in such a scheme for streams more complicated than
file-streams.  We discussed string-stream-like approaches where buffers
need to be exchanged after writing them to the device, and with this
approach the device methods would need to access the buffering object, a
layering violation?  Perhaps a question that can only be answered when
there is also a proposed design for the buffering layer.

| @smalldisplay
| ;;;; rudi (2004-07-09): we should also specify the conditions that are
| ;;;; thrown, if any.  My gut feeling would be to work with return
| ;;;; values only and throw conditions farther up, what do you think?
| @end smalldisplay

So EOF is not a condition here because it is not really an exceptional
situation, but rather expected.  Fine.  Actual errors, however, should
be conditions, I think.  (- -10 errno) does not look very lispy to me...

| @defun device-open device &rest initargs @result{} result
| @var{device}: an instance of device-stream
| @var{initargs}: options specific to the actual type of @var{device}
| @var{result}: a generalized boolean
| @code{device-open} performs the device-specific operations to open the
| underlying device, taking any needed information from @var{initargs}.
| @var{result} is true if the device could be successfully opened, false
| if not.
| @end defun

Can you elaborate on that?  Given that CLOS is used here anyway, why is
initialization of the stream not done by INITIALIZE-INSTANCE and
friends?  I know that simple streams have a DEVICE-OPEN method, but I am
unclear about why that was invented, too.

Is it necessary to be able to create streams and open them only later?
Or can streams be re-opened?

| @defun device-close device
| @var{device}: an instance of device-stream
| @code{device-close} closes the underlying device.
| @end defun

Might need an ABORT argument?

| @defun device-read device buffer start end blocking @result{} result
| @defun device-write device buffer start end blocking @result{} result

Sounds good.

| @defun device-clear-input device
| @var{device}: an instance of @code{device-stream}
| @code{device-clear-input} performs any device-specific operations necessary
| to discard any input pending on the underlying device, including
| clearing any os-level buffers or similar.
| @end defun

The only correct implementation I can imagine for this function with
Unix files is to loop in read() until nothing more is returned.  Bad
idea with, say, /dev/random, because it will loop forever.  Is this
really what is meant?  If not, can we make it more precise or just drop
it completely?

| @defun device-clear-output device
| @var{device}: an instance of @code{device-stream}
| @code{device-clear-output} performs any device-specific operations necessary
| to discard any output pending on the underlying device, including
| clearing any os-level buffers or similar.
| @end defun

Similar question as for clear-input: This sounds like the device layer
implementation of CLEAR-OUTPUT.  Taking Unix file descriptors an an
example, how would this work?  (If there is no reasonable implementation
of this on current operating systems, why not assume that CLEAR-OUTPUT
flushes the higher-level buffer, but does not reach the device layer at

| @defun device-flush-output device blocking
| @smalldisplay
| ;;;; rudi (2004-10-09): device-flush-output instead of
| ;;;; device-finish-output, device-force-output since the blocking
| ;;;; parameter exists everywhere else as well (it seems more in line
| ;;;; with the other methods, but I don't insist on this change)
| @end smalldisplay

| @var{device}: an instance of @code{device-stream}
| @var{blocking}: a generalized boolean
| @code{device-flush-output} performs any device-specific operations
| necessary to flush any output pending on the underlying device.  If
| @var{blocking} is true, @code{device-flush-output} will make a best effort to
| block until the underlying device confirms completion of the output.
| If @var{blocking} is false, @code{device-finish-output} returns immediately.
| @end defun

To clarify, with a unix file, this should be fsync(),right?

(I have always assumed that FORCE-OUTPUT flushes a stream's buffer, and
FINISH-OUTPUT does more: It calls fsync().  In reality, the Lisps I have
looked at just flush the buffer for both functions. :()

On the BLOCKING argument: Not sure.  Assuming it is possible, what good
does syncing do when you do not wait for it to complete?

| @defun (setf device-file-position) device new-position @result{} result

@defun (setf device-file-position) new-position device @result{} result

Wishlist item: I have often missed a portable function FILE-TRUNCATE.
Would such a function fit into this interface?


More information about the Streams-standard-discuss mailing list