This is an addition to coredump's answer. In particular I think that the behaviour of your code is correct: SBCL is doing the right thing in its implementation of Gray streams, and it should indeed be signalling an exception here.
In your code the pattern of calls is:
read-byte (with no optional arguments) on your binary-input-stream calls stream-read-byte on the same stream;
- your method on
stream-read-byte directly calls read-byte on the stream you have wrapped, asking for no error and a return on EOF of :eof, and returns the value of that call without further inspection;
- that in turn presumably goes through the
stream-read-byte method of the wrapped stream, but we don't need to worry about that.
So, what should this do? Well, I am not sure where the right place for the definitive documentation of Gray streams is, but here is something which may be close to it.
In that document, stream-read-byte is defined:
STREAM-READ-BYTE stream [Generic Function]
Used by READ-BYTE; returns either an integer, or the symbol :EOF if the
stream is at end-of-file.
read-byte is then defined as:
(defun READ-BYTE (binary-input-stream &optional (eof-errorp t) eof-value)
(check-for-eof (stream-read-byte binary-input-stream)
binary-input-stream eof-errorp eof-value))
Finally check-for-eof is defined as:
(defun check-for-eof (value stream eof-errorp eof-value)
(if (eq value :eof)
(report-eof stream eof-errorp eof-value)
value))
(I think the last two definitions really mean that 'the implementation needs to do something whose behaviour is equivalent to this', and in particular it needs to do that in the case where the stream is a Gray stream.)
So any method on stream-read-byte must not return :eof unless the stream is at end of file, and in particular doing so will cause an exception to be signalled (or will cause report-eof to be invoked, anyway, and it may or may not signal an exception). And :eof is the only special value that stream-read-byte can return.
Well, your method on stream-read-byte does indeed return :eof to indicate end of file, having carefully suppressed the exception that the inner call yo read-byte would otherwise signal, so it's a well-behaved method.
But then the outer call to read-byte, as defined above, sees this EOF value and dutifully raises an exception for you. Which is, in fact, what you asked for, because you did not ask to suppress the exception in those calls.
If you don't want an exception you need to make sure that the outer calls to read-byte ask for one not to happen, by, for instance:
(with-open-file (in "test.txt" :element-type '(unsigned-byte 8))
(with-open-stream (bin (make-binary-input-stream in))
(values (read-byte bin nil ':eof)
(read-byte bin nil ':eof))))
For a one-byte file this should return the byte in the file and :eof.