Dear all,
I ran into something I don't quite understand about the treatment of closed streams.
Take a closed stream handle:
open(f, write, W), close(W), open(f, read, S), close(S)
then:
set_input(S) stream_property(S, _)
reports existence_error(stream,S) while the ISO standard expects that:
current_input(S)
reports domain_error(stream, S).
On the implementation side, it feels natural to share stream checking code, which would lead to a more uniform existence_error(stream,S) error for the three predicates (like SWI Prolog does).
Am I missing something?
Thanks,
about the treatment of closed streams.
Closed streams are still of the form a stream. Thus any attempt to use them any further will either lead to
- an existence error
?- open('/tmp/myfile',write,S),close(S), close(S). existence_error(stream, ...).
- failure, in case of a query about it
?- open('/tmp/myfile',write,S), close(S), current_input(S). false.
A domain error is only appropriate if the term can never be a stream-term. This indeed depends on an implementation which has here some freedom see 7.10.2.1.
?- close(1+1). domain_error(stream_or_alias,1+1). % provided 1+1 is not chosen ...
On Tue, Jun 9, 2026 at 2:37 PM Ulrich Neumerkel < ulrich@a4.complang.tuwien.ac.at> wrote:
about the treatment of closed streams.
Closed streams are still of the form a stream. Thus any attempt to use them any further will either lead to
- an existence error
?- open('/tmp/myfile',write,S),close(S), close(S). existence_error(stream, ...).
- failure, in case of a query about it
?- open('/tmp/myfile',write,S), close(S), current_input(S). false.
Thanks, that resolves it. To confirm I've understood: a closed handle is still a stream-term (the right kind of term), so the domain_error clause of 8.11.1.3 does not apply. Since current_input/1 is a query, it simply fails. I've checked that GNU Prolog works that way. SICStus, Trealla, or SWI does not.
Just to follow:
- current_input/1 lists only domain_error(stream, S) and no existence_error.
So SWI returning existence_error(stream, S) here raises an error the predicate's table does not allow.
- By your reasoning, SICStus's domain_error(stream, S) is equally non-conforming for a closed handle: domain_error is appropriate only when the term can never be a stream-term, which a closed handle can be. That is what some conformance suite currently (incorrectly?) encodes as the expected result, e.g. LogTalk:
https://github.com/LogtalkDotOrg/logtalk3/blob/36a64c4d24448813af25c48a1966c...
https://github.com/LogtalkDotOrg/logtalk3/blob/36a64c4d24448813af25c48a1966c...
- stream_property/2 only lists domain_error(stream, S), no existence_error.
I understand that stream_property/2 on a closed stream must also fail and not raise an existence error. Same suite's expectation for the closed-handle cases:
https://github.com/LogtalkDotOrg/logtalk3/blob/36a64c4d24448813af25c48a1966c...
https://github.com/LogtalkDotOrg/logtalk3/blob/36a64c4d24448813af25c48a1966c...
A domain error is only appropriate if the term can never be a
stream-term. This indeed depends on an implementation which has here some freedom see 7.10.2.1.
?- close(1+1). domain_error(stream_or_alias,1+1). % provided 1+1 is not chosen ...
Just one impromptu correction:
SICStus **does** conform here, however the top-level loop (out of scope of the standard) shows something different.
ICStus 4.9.0 (x86_64-linux-glibc2.28): Fri Dec 15 10:08:12 UTC 2023 Licensed to UlrichNeumerkel | ?- open('/tmp/myfile',write,S),close(S), close(S). ! Domain error in argument 1 of close/1 ! expected stream, but found '$stream'(127661962395680) ! goal: close('$stream'(127661962395680)) | ?- open('/tmp/myfile',write,S),close(S), catch(close(S),error(E,_),true). S = '$stream'(127661984026720), E = existence_error(stream,'$stream'(127661984026720)) ? ; no
So just the second query shows us what we want to see, but before SICStus produced this domain error (which now is found in the second argument of error/2)
Also, Trealla fixed this already!
On 09/06/2026 17:30, Jose F. Morales wrote:
- failure, in case of a query about it
?- open('/tmp/myfile',write,S), close(S), current_input(S). false.
So, this indeed raises an existence error in current SWI-Prolog. I looked at it in a bit more detail. This raises some questions:
?- current_input(4.5) raises a domain error.
What should the call below do? After all, foo can be a stream alias name that either exists, has existed or has never existed.
?- current_input(foo).
Turning the above into failure also turns this into a failure. SICStus raises a domain error.
P.s. Although I think failing is logically more sound, systems must be able to safely deal with the ABA issue, i.e., a stream handle is closed and a new stream is opened using the same term. This cannot happen in SWI-Prolog because stream handles are "blobs" that are subject to Atom-GC and a stream handle can thus only be reclaimed after the old was reclaimed by atom-GC
Regards --- Jan
On Tue, Jun 9, 2026 at 5:57 PM Jan Wielemaker jan@swi-prolog.org wrote:
[...]
What should the call below do? After all, foo can be a stream alias
name that either exists, has existed or has never existed.
?- current_input(foo).Turning the above into failure also turns this into a failure. SICStus raises a domain error.
Just a comment: if I am not wrong, ISO does not allow aliases in current_input/1.
P.s. Although I think failing is logically more sound, systems must be
able to safely deal with the ABA issue, i.e., a stream handle is closed and a new stream is opened using the same term. This cannot happen in SWI-Prolog because stream handles are "blobs" that are subject to Atom-GC and a stream handle can thus only be reclaimed after the old was reclaimed by atom-GC
Ciao (still) has no proper atom-GC but we keep the object around (marked as "closed") until it is reclaimed. I think we are safe too.
Regards --- Jan
Prolog-standard mailing list -- prolog-standard@software.imdea.org To unsubscribe send an email to prolog-standard-leave@software.imdea.org
ISO does not allow aliases in current_input/1.
Correct. This can be seen already from the precise error produced:
?- current_input(alias). domain_error(stream,alias).
Thus the domain is stream. But with close/1:
?- close(1+1). domain_error(stream_or_alias,1+1).
Justification in 7.10.2.2 Note 2.
Or from the corresponding Template and Modes sections.
prolog-standard@software.imdea.org