Subject: [clisp-list] Re: Can CLOSE signal an error? (was: CHARSET questio ns & early vs late error signaling)

From: "Hoehle, Joerg-Cyril" <[email-masked]>
Date: Tue Aug 20 08:59:03 2002

Sam Steingold wrote:
>Your logic dictates that CLOSE must check all streams for being the
>value of *STANDARD-OUTPUT*, *STANDARD-INPUT*, *QUERY-IO* &c &c &c &c.
No. That's why I tried to be very precise and said
(close #<the terminal io object>), not (close *terminal-io*).
In every session, there's a (generally unique) such thing, while *terminal-io* may be bound to anything, likewise *standard-output*.

So the only chek I once had was in the C
low_level_close(object stream)
 { switch strm_type(object) {
     case strm_type_xyz: ....; break;
     case strm_type_terminal:
       raise error; } }

>What behavior would you expect from
>        (CLOSE *TERMINAL-IO*) ==> ?
>An error, right?
Depends on the value of the binding.
(let ((*terminal-io* (make-broadcast-stream))) (close *terminal-io*))
 -> no error.

I said "generally unique" because it's precisely at the time, many years ago, when I pointed at the problem of possibly closing the terminal-io object that Bruno added make_terminal_stream() which would 1) create a new such object if needed, and 2) bind *terminal-io* etc. to this newly created sane object.
In my version I had a unique such object that I did revive.

>Let us step back and ask: what problem are we trying to solve here?
>I seem to recall vaguely that the problem was that the closed terminal
>stream was causing a crash - right?
or was it throwing an error?
>In that case, we should build --with-debug and see why it was closed in
>the first place.
In my perception it's a GC like problem: the crash occurs much later than the fault. It's only when trying to access the #<closed terminal io object> that a program would be hit by the error.

That was an example for late early reporting in CLISP.

OTOH, another scenario: Suppose *foreign-encoding* would be true special variables, so the 1:1 restriction detection could only occur while calling a foreign function, not at SETF time.
Hmm... maybe using Lisp backtrace, one could still easily spot the place where this bindings takes place -- if it's a LET binding that gives the value, not a SETF. So the ease of spotting bogus values of *foreign-encoding* depends on a programers' custom: do the programmers use LET for the special variable, or SETF?

It seems every scenario may have differing forces/priorities/ease of spotting bugs/

BTW, I don't like --with-debug. It's C level debugging, while I prefer
to work in Lisp. The Lisp programmer should be able to find out what
went wrong in his/her Lisp application via the usual helpers like
Lisp backtrace, Lisp tracing or Lisp-level stepping, not by running
gdb against the C stack. In 10 years of working on/with CLISP, I only
used gdb when looking for gcc bugs or some things at the C level.
Which doesn't mean that a C backtrace doesn't reveal insightful things...

Regards,
	Jorg Hohle.

---

From: Sam Steingold <[email-masked]>
Date: Tue Aug 20 09:47:06 2002

> * In message <[email-masked]>
> * On the subject of "[clisp-list] Re: Can CLOSE signal an error? (was: CHARSET questio ns & early vs late error signaling)"
> * Sent on Tue, 20 Aug 2002 17:58:12 +0200
> * Honorable "Hoehle, Joerg-Cyril" <[email-masked]> writes:
>
> Sam Steingold wrote:
that's what I meant too - you misunderstood me!
please read my message again.

> In every session, there's a (generally unique) such thing, while
> *terminal-io* may be bound to anything, likewise *standard-output*.
sure.

> I said "generally unique" because it's precisely at the time, many
> years ago, when I pointed at the problem of possibly closing the
> terminal-io object that Bruno added make_terminal_stream() which would
> 1) create a new such object if needed, and 2) bind *terminal-io*
> etc. to this newly created sane object. 

I see no difference between creating a new object and reviving the old
one.
The only difference that matters here is whether you permit closing
#<terminal-io> or not.
Or maybe you want fehler_value_stream() to restore the values silently
instead of signaling an error? Or make the error continuable?

if you want to detect closing system i/o streams, it is not enough to
forbid closing #<terminal-io> because, as I explained in the previous
message, *standard-output* is not bound to such values!
try the appended patch and see for yourself.

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat7.3 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
You think Oedipus had a problem -- Adam was Eve's mother.

--- stream.d.~1.307.~	Mon Aug 12 10:05:28 2002
+++ stream.d	Tue Aug 20 09:50:40 2002
@@ -10505,10 +10505,7 @@
 
 # Returns an interactive Terminal-Stream.
 # can trigger GC
-local object make_terminal_stream (void) {
-  return add_to_open_streams(make_terminal_stream_());
-}
-
+#define make_terminal_stream() make_terminal_stream_()
 
 # Window-Stream
 # =============
@@ -16154,7 +16151,7 @@
     #ifdef KEYBOARD
     case strmtype_keyboard: break;
     #endif
-    case strmtype_terminal: break;
+    case strmtype_terminal: fehler_illegal_streamop(S(close),stream);
     #ifdef SCREEN
     case strmtype_window: close_window(stream); break;
     #endif
--- constsym.d.~1.161.~	Tue Aug  6 15:55:46 2002
+++ constsym.d	Tue Aug 20 09:43:28 2002
@@ -915,6 +915,7 @@
 LISPSYM(set_stream_external_format,"SET-STREAM-EXTERNAL-FORMAT",system)
 LISPSYM(interactive_stream_p,"INTERACTIVE-STREAM-P",lisp)
 LISPSYM(built_in_stream_close,"BUILT-IN-STREAM-CLOSE",system)
+LISPSYM(close,"CLOSE",lisp)     /* error reporting in stream.d */
 LISPSYM(read_byte,"READ-BYTE",lisp)
 LISPSYM(read_byte_lookahead,"READ-BYTE-LOOKAHEAD",ext)
 LISPSYM(read_byte_will_hang_p,"READ-BYTE-WILL-HANG-P",ext)