Currently learning Common Lisp with SBCL, and it's bugging me how query-io has some unexpected differences from standard input and output. I will assume that standard-output contains a newline, or is formatted with one, because
(format *query-io* "hello")
Contains no newline at all.
Now, using read-line gives me this behavior
(defun read (prompt)
(format *query-io* "~a: " prompt)
(read-line))
(read "message")
> hello
"hello"
message: NIL
I was told this is expected, as SBCL would wait for a newline to be inputted before printing the format, but what I don't get is the result of changing the second line
(defun read (prompt)
(format *standard-output* "~a: " prompt)
(read-line))
(read "message")
> hello
message:
"hello"
NIL
Why is the order different? I don't think the newline after the prompt variable affects the result
If you want things to behave in a predictable way you should write programs which ensure that:
read
(in fact I'm extremely convinced that SBCL wouldn't have allowed you to name the function read
, unless perhaps you are using a prehistoric version);So in your first function you are doing something equivalent to what I assume is this:
(defun f1 (prompt)
(format *query-io* "~a: " prompt)
(read-line))
This:
*query-io*
, which means that at some future time it may appear on whatever *query-io*
points at;*standard-input*
;So if you call this function it will read a line from *standard-input*
which perhaps is the terminal but may not be. At some time after the call to format
some output probably will appear on *query-io*
which may also point at the terminal. There is no guarantee as to when or in fact even if that output will appear: for instance if you modify the function to be:
(defun f1.1 (prompt)
(format *query-io* "~a: " prompt)
(clear-output *query-io*)
(read-line))
it is quite possible that the prompt will never appear.
When output actually appears from functions which write to streams if you don't explicitly say 'write it now' depends on many, many factors:
clear-output
on the stream and whether clear-output
actually does anything;:abort t
and whether that actually does anything;In your second function things are mostly the same:
(defun f2 (prompt)
(format *standard-output* "~a: " prompt)
(read-line))
This time format
is writing to *standard-output*
, not *query-io*
and again you are reading a line from *standard-input*
. And again, when and if the output from format
appears is in the lap of the gods.
So what you need to do is
In particular never make assumptions that output written to some stream appears at any given point 'on its own' or 'after a newline', or anything like that.
If you want to prompt and read from *query-io*
you do it like this:
(defun f3 (prompt)
(format *query-io* "~a: " prompt)
(finish-output *query-io*)
(read-line *query-io*))
If you want to prompt on *standard-output*
and read from *standard-input*
then:
(defun f4 (prompt)
(format *standard-output* "~a: " prompt)
(finish-output *standard-output*)
(read-line *standard-input*))
In this last case you can actually leave out the streams (and use t
for format
) because they are the defaults: still it is probably better to be explicit.
f3
is probably better, since prompting and reading is what *query-io*
is for.