Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CLOSE and OUTPUT-STREAM-P

33 views
Skip to first unread message

Sam Steingold

unread,
Mar 31, 2002, 10:31:25 PM3/31/02
to
what should OUTPUT-STREAM-P/INPUT-STREAM-P return for closed streams?

CLHS:

input-stream-p returns true if stream is an input stream;
otherwise, returns false.

input adj. (of a stream) supporting input operations (i.e.,
being a ``data source''). An input stream might also be an
output stream, in which case it is sometimes called a
bidirectional stream. See the function input-stream-p.

Clearly a closed stream is not a "data source".
OTOH, an example in the page for CLOSE says:

(setq s (make-broadcast-stream)) => #<BROADCAST-STREAM>
(close s) => T
(output-stream-p s) => true

so -- are CLISP & CMUCL in error when their
OUTPUT-STREAM-P/INPUT-STREAM-P return NIL for closed streams?

thanks.

--
Sam Steingold (http://www.podval.org/~sds) running RedHat7.2 GNU/Linux
Keep Jerusalem united! <http://www.onejerusalem.org/Petition.asp>
Read, think and remember! <http://www.iris.org.il> <http://www.memri.org/>
When we write programs that "learn", it turns out we do and they don't.

Nils Goesche

unread,
Mar 31, 2002, 11:11:19 PM3/31/02
to
Sam Steingold <s...@gnu.org> writes:

> what should OUTPUT-STREAM-P/INPUT-STREAM-P return for closed streams?
>
> CLHS:
>
> input-stream-p returns true if stream is an input stream;
> otherwise, returns false.
>
> input adj. (of a stream) supporting input operations (i.e.,
> being a ``data source''). An input stream might also be an
> output stream, in which case it is sometimes called a
> bidirectional stream. See the function input-stream-p.
>
> Clearly a closed stream is not a "data source".
> OTOH, an example in the page for CLOSE says:
>
> (setq s (make-broadcast-stream)) => #<BROADCAST-STREAM>
> (close s) => T
> (output-stream-p s) => true
>
> so -- are CLISP & CMUCL in error when their
> OUTPUT-STREAM-P/INPUT-STREAM-P return NIL for closed streams?

What if a source is exhausted? Or poisened? Or simply
forbidden? Does it cease being a source anymore?

Regards,
--
Nils Goesche
Ask not for whom the <CONTROL-G> tolls.

PGP key ID 0xC66D6E6F

Kent M Pitman

unread,
Apr 1, 2002, 3:34:24 AM4/1/02
to
Sam Steingold <s...@gnu.org> writes:

> what should OUTPUT-STREAM-P/INPUT-STREAM-P return for closed streams?
>
> CLHS:
>
> input-stream-p returns true if stream is an input stream;
> otherwise, returns false.
>
> input adj. (of a stream) supporting input operations (i.e.,
> being a ``data source''). An input stream might also be an
> output stream, in which case it is sometimes called a
> bidirectional stream. See the function input-stream-p.
>
> Clearly a closed stream is not a "data source".
> OTOH, an example in the page for CLOSE says:
>
> (setq s (make-broadcast-stream)) => #<BROADCAST-STREAM>
> (close s) => T
> (output-stream-p s) => true
>
> so -- are CLISP & CMUCL in error when their
> OUTPUT-STREAM-P/INPUT-STREAM-P return NIL for closed streams?

Absent some clarification from the committee, I'd be hard-pressed to say
that either NIL or T was a bad return value here.

I certainly wouldn't rely to heavily on the meaning of something in
scare-quotes, which is obviously trying not to have very definite
meaning.

I believe the complexity of the definitions on these is supposed to
accomodate situations where "close" called on an interactive stream
doesn't really close it... some Lisp implementations don't support the
weird Unix-esque notion that there can be an eof on a terminal input
stream. Consequently, we were vague about the action of CLOSE.

Portable programs must not access a closed stream, but portable
programs MIGHT be repeatedly called interactively on certain streams
that the user knows didn't get closed for implementation-defined reasons.

Also, some implementations might have streams that morph in nature between
inputness and outputness upon CLOSE or some other action. I think
INPUT-STREAM-P and OUTPUT-STREAM-P are intended to guide you as to
what kinds of things you are intended to do on an object you've just found.
In this regard, I would say it's most important that if you do
(input-stream-p x) => t
on a closed stream, you are implying that peeking for data on the
stream is going to yield eof information without a problem and not complain
that it was improper for you to do this. Analogously for OUTPUT-STREAM-P.

For just a moment here, I want to use a term "fresh" from English
parlance here, not the usage in the CL glossary, in order to make a
point by analogy. It took me a long time in my youth to understand
the meaning of the term "fresh" that women would cry out when they
would slap boys for trying to kiss them on a date. I think the term
is sometimes abused, and so its meaning is hard to discern. But I
finally found a coherent explanation: the idea is that there is a time
during which a relationship is too "fresh" for a kiss to even be
attempted. If you try, you should expect to be rebuffed because it is
a protocol error to make the attempt. Later in a relationship, you
pass a point where the default becomes that it is reasonable for you
to try but you still are not guaranteed a good result. The girl (or
woman, but they were girls at the boyish age I learned this) may say
"no thank you" but may not be angry with you for the attempt. That is
the point at which the relationship is no longer fresh, and a
different protocol applies. It is always permitted that the girl say
"no", but the class of the error is different. [The book I read this
in went on to to give specific date numbers for kisses and other such
"behaviors", which specific numbers I'm doubtful of only because I've
never seen these date numbers published any other place and I doubt
their common knowledge. Even so, though, the structure of the
metaphor was quite instructive as to the intent of a word I had never
imagined could yield to so rigorous an explanation.]

As a personal opinion, going back to to INPUT-STREAM-P and
OUTPUT-STREAM-P, I believe that its job is to tell you whether the
attempt to use these operations will be received as
of "fresh" or not. [We're not talking "kiss" protocols here, of course,
we're talking "handshake" protocols. Heh...]
If you plan to support the full array of input stream operations,
responding as if it was appropriate to ask them and that you are just
at EOF, I think you are probably ok returning T for INPUT-STREAM-P.
If when you did CLOSE, you did something to the stream internally that
makes these operations no longer apply, such as do something like
(setf (my-internal-dispatch-table stream)
(remove-internal-stream-module input-operations
(my-internal-dispatch-table stream)))
then you had better return information that warns people off from even
trying the input operations.

But that's just my personal opinion. YMMV.

Erik Naggum

unread,
Apr 1, 2002, 5:35:52 AM4/1/02
to
* Sam Steingold <s...@gnu.org>

| what should OUTPUT-STREAM-P/INPUT-STREAM-P return for closed streams?

Same as for the open stream, of course. The stream was created for
output or input or both. If you want to know if it is also open,
open-stream-p provides that answer. It is possible determine that a
stream is closed but was used for output in the current design. If you
make these predicates test for open-stream-p first, you remove the
ability of a program to test for what a stream was before it was closed.
If you conflate these two predicates, you actually destroy information.
Please do not destroy information just because you would like to avoid
writing more code.

///
--
In a fight against something, the fight has value, victory has none.
In a fight for something, the fight is a loss, victory merely relief.

Brian Spilsbury

unread,
Apr 1, 2002, 6:52:03 AM4/1/02
to
Nils Goesche <n...@cartan.de> wrote in message news:<87663c5...@darkstar.cartan>...

http://www.xanalys.com/software_tools/reference/HyperSpec/Issues/iss053_w.htm

"There was some discussion on whether INPUT-STREAM-P and
OUTPUT-STREAM-P
should return "false" on a stream that had been closed. The issue
STREAM-ACCESS contains a proposal to add a function OPEN-STREAM-P
which might be useful for the same purpose. This issue was separated
out into a separate issue (INPUT-STREAM-P-CLOSED)."

So there is some controversy.

Unfortunately the issue INPUT-STREAM-P-CLOSED doesn't appear to be on
the xanalysis site.

I think that CLISP and CMUCL are in error, since those are primarily
type predicates, and the type hasn't changed, imho, but there seems to
be enough give in the spec here to allow either behaviour.

If someone does find issue (INPUT-STREAM-P-CLOSED), I'd be interested
in reading it too.

Regards,

Brian

Erik Naggum

unread,
Apr 1, 2002, 7:14:11 AM4/1/02
to
* Kent M Pitman <pit...@world.std.com>

| I think INPUT-STREAM-P and OUTPUT-STREAM-P are intended to guide you as
| to what kinds of things you are intended to do on an object you've just
| found.

Agreed.

| In this regard, I would say it's most important that if you do
| (input-stream-p x) => t
| on a closed stream, you are implying that peeking for data on the stream
| is going to yield eof information without a problem and not complain that
| it was improper for you to do this. Analogously for OUTPUT-STREAM-P.

Here I disagree. If you are going to attempt any operations on a stream,
open-stream-p gives the authoritative answer on whether any I/O will work
on it, not whether it is an input-stream or an output-stream.

Kent M Pitman

unread,
Apr 1, 2002, 7:51:51 AM4/1/02
to
Erik Naggum <er...@naggum.net> writes:

> * Kent M Pitman <pit...@world.std.com>
> | I think INPUT-STREAM-P and OUTPUT-STREAM-P are intended to guide you as
> | to what kinds of things you are intended to do on an object you've just
> | found.
>
> Agreed.
>
> | In this regard, I would say it's most important that if you do
> | (input-stream-p x) => t
> | on a closed stream, you are implying that peeking for data on the stream
> | is going to yield eof information without a problem and not complain that
> | it was improper for you to do this. Analogously for OUTPUT-STREAM-P.
>
> Here I disagree. If you are going to attempt any operations on a stream,
> open-stream-p gives the authoritative answer on whether any I/O will work
> on it, not whether it is an input-stream or an output-stream.

Although a stream like an HTTP stream might be effectively only open in
one direction or the other at any given time even though continuously
open... I don't know that I advocate that INPUT-STREAM-P be the right way
to test this, but I don't think I'd scream if some vendor thought it was.

Sam Steingold

unread,
Apr 1, 2002, 1:04:22 PM4/1/02
to
Okay, what about things like STREAM-ELEMENT-TYPE and
STREAM-EXTERNAL-FORMAT?

I take it that Erik Naggum will say that CLOSE should not change the
return values of these functions.

What about Kent?


--
Sam Steingold (http://www.podval.org/~sds) running RedHat7.2 GNU/Linux
Keep Jerusalem united! <http://www.onejerusalem.org/Petition.asp>
Read, think and remember! <http://www.iris.org.il> <http://www.memri.org/>

Life is like a diaper -- short and loaded.

Kent M Pitman

unread,
Apr 1, 2002, 1:21:52 PM4/1/02
to
Sam Steingold <s...@gnu.org> writes:

> Okay, what about things like STREAM-ELEMENT-TYPE and
> STREAM-EXTERNAL-FORMAT?
>
> I take it that Erik Naggum will say that CLOSE should not change the
> return values of these functions.
>
> What about Kent?

It's curious in retrospect that we didn't have
INPUT-STREAM-ELEMENT-TYPE and OUTPUT-STREAM-ELEMENT-TYPE since in
principle the two directionalities don't seem they have to be the
same. Given there is only one function, I guess this imposes an
artificial restriction that they two be the same.

I think CLOSE probably renders uninteresting the question of whether
a stream has an element type, but if you find a stream you can't tell
except by the available discovery operations whether it's open, and
so if it professes to be open, notwithstanding a prior CLOSE that you
can't know about, then I think STREAM-ELEMENT-TYPE should work; if it
doesn't profess to be open, I think the operation isn't needed.

Ditto STREAM-EXTERNAL-FORMAT, I guess.

But again, these are just my reasoned opinions about what would make
sense as "what to do".

My sense of what you're allowed to do might be more forgiving.

And certainly, as always, I am just opinion.

Erik Naggum

unread,
Apr 1, 2002, 2:20:34 PM4/1/02
to
* Sam Steingold <s...@gnu.org>

| Okay, what about things like STREAM-ELEMENT-TYPE and
| STREAM-EXTERNAL-FORMAT?
|
| I take it that Erik Naggum will say that CLOSE should not change the
| return values of these functions.

Yes. I regard close as modifying one property of a stream, because it is
important to be able to reopen the stream correctly after it has been
closed.

Duane Rettig

unread,
Apr 1, 2002, 4:00:01 PM4/1/02
to
Erik Naggum <er...@naggum.net> writes:

> * Sam Steingold <s...@gnu.org>
> | Okay, what about things like STREAM-ELEMENT-TYPE and
> | STREAM-EXTERNAL-FORMAT?
> |
> | I take it that Erik Naggum will say that CLOSE should not change the
> | return values of these functions.
>
> Yes. I regard close as modifying one property of a stream,

I agree that close modifies a property of the stream, but I also
believe that that particular property (i.e. the actual connection
with the "file" it is associated with) is precisely the fundamental
property of the stream which makes the stream useful as a stream.
Therefore I would expect that accessors which have only to do with
the internal representation of the stream object would probably not
change what they return after the stream is closed, but that
accessors which deal with the connection itself might not return
the same value, and in fact might invoke an error.

> because it is
> important to be able to reopen the stream correctly after it has been
> closed.

But what does it actually mean to "reopen" a stream? CL only defines
opening and closing, and the concept of reopening depends on the state
of the file which we want to "open again", e.g. establish a connection
between the (possibly reused) stream object and the "file" that had
previously been opened to it [I'm using the CL description for closing
a file associated with a file-stream, here; it may be that the object
being connected to is not a file; it may be a socket or other external
object, and it may not even be external, as is the case for a string
stream]. If the file is external and in fact externally changeable,
there may be no way to reestablish a connection that looks the same
as the one previously established. One example of this is the BSD
style of temporary file establishment, in which one creates a file,
opens it, and then unlinks the file. The file then exists only
while it is open, and as soon as the file descriptor is closed,
the file itself is lost, and can thus not be reopened. The same
is true for a file which is renamed externally; unless the new name
or location is fed back and made available to the stream-opening
mechanism in some way, the old path might not be usable to get a
handle on the previously opened file.

I am not arguing against saving as much information as possible for
the subsequent reopening of a stream if possible, but I am warning
that such reopening might not be possible.

--
Duane Rettig Franz Inc. http://www.franz.com/ (www)
1995 University Ave Suite 275 Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253 du...@Franz.COM (internet)

Erik Naggum

unread,
Apr 1, 2002, 5:09:40 PM4/1/02
to
* Duane Rettig <du...@franz.com>

| But what does it actually mean to "reopen" a stream?

To use the information that a stream known about itself to open the same
source again in precisely the same way it was first opened. If this were
not possible, one would have to associate the stream with some hash table
or something else that keeps this information around, but there is no way
to make a stream point back to such information, so if you have to do
these things, it creates a hairy information maintenance and consistency
problem. E.g., a stream, even a closed stream, is a pathname designator.

I do not mean to "reuse" the streams object, although it would be very
convenient if open could take an open stream and return a clone or a
closed stream and return a new open stream to the same object insofar as
that be possible.

| If the file is external and in fact externally changeable, there may be
| no way to reestablish a connection that looks the same as the one
| previously established.

But this may be intentional, like a file-position back to the beginning
of the file may cause subsequent read-char calls to return different
values than last time because the file has been independently modified.

| I am not arguing against saving as much information as possible for the
| subsequent reopening of a stream if possible, but I am warning that such
| reopening might not be possible.

Well, you have no guarantee that you can read the data that was in the
file at the time it was opened, either. One needs to be aware of such
things when dealing with the hostile external world. I am not arguing
for a change to the universe in order to get a desired feature.

Duane Rettig

unread,
Apr 1, 2002, 8:00:01 PM4/1/02
to
Erik Naggum <er...@naggum.net> writes:

> * Duane Rettig <du...@franz.com>
> | But what does it actually mean to "reopen" a stream?
>
> To use the information that a stream known about itself to open the same
> source again in precisely the same way it was first opened.

OK.

> If this were
> not possible, one would have to associate the stream with some hash table
> or something else that keeps this information around, but there is no way
> to make a stream point back to such information,

If the stream supports a property list of some sort, it is possible.

> so if you have to do
> these things, it creates a hairy information maintenance and consistency
> problem. E.g., a stream, even a closed stream, is a pathname designator.

Agreed.

> I do not mean to "reuse" the streams object, although it would be very
> convenient if open could take an open stream and return a clone or a
> closed stream and return a new open stream to the same object insofar as
> that be possible.

Yes, this would be possible, for example with our simple-streams
design (not with open, per se, but with some option to device-open
through the make-instance or reinitialize-instance method).

You might also want to allow modifications in such reopen calls, similar
to the C freopen(), which asks for a new mode to be specified
(though it could be optional in the Lisp version).

> | If the file is external and in fact externally changeable, there may be
> | no way to reestablish a connection that looks the same as the one
> | previously established.
>
> But this may be intentional, like a file-position back to the beginning
> of the file may cause subsequent read-char calls to return different
> values than last time because the file has been independently modified.
>
> | I am not arguing against saving as much information as possible for the
> | subsequent reopening of a stream if possible, but I am warning that such
> | reopening might not be possible.
>
> Well, you have no guarantee that you can read the data that was in the
> file at the time it was opened, either. One needs to be aware of such
> things when dealing with the hostile external world. I am not arguing
> for a change to the universe in order to get a desired feature.

Right. So given that we seem to agree that there is a chance for
external interference, and disregarding those cases, I suggest that
any state which can be saved (e.g., in a plist slot) before the close
could also be used at reopen time to get back the same connection,
modulo any external changes. This would give the implementation the
leeway to decide what to return, for example, for output-stream-p after
closing, and still meet your requirement for reopenability.

Note though that the reopenability requirement would have to be
specified on a case-by-case basis, or with a general rule. You might
want the stream reopened as it was at open time, or as it was at close
time. For example, a socket might be opened bidirectionally, and a
shutdown on the output side might unset a bit, or in a situation where
the class determines the directional openness the shutdown might
result in a change-class, but at any rate you would have to specify
whether you wanted the socket to be reopened bidirectionally or in the
input direction only (since that was how it had been closed).

Erik Naggum

unread,
Apr 2, 2002, 2:15:16 AM4/2/02
to
* Duane Rettig

| Right. So given that we seem to agree that there is a chance for
| external interference, and disregarding those cases, I suggest that
| any state which can be saved (e.g., in a plist slot) before the close
| could also be used at reopen time to get back the same connection,
| modulo any external changes. This would give the implementation the
| leeway to decide what to return, for example, for output-stream-p after
| closing, and still meet your requirement for reopenability.

Yes. My position is simply that no information should be wantonly
destroyed even if it cannot be used to recover completely a previous
state. I cherish the ability of Common Lisp streams to know which file
they opened. This is mostly useful during error handling, of course, but
the kind of reopening I have in mind would be useful if you want to give
the user the ability to edit a configuration file (or source code of a
program) and restart interpretation/reading/whatever, but could not
guarantee that the file you refer to in the open stream would change, but
the new version might have exactly the same name and be re-openable where
the stream could not be returned to its beginning.

0 new messages