I am working with Allegro CL 11.0 Express Edition on Linux (Ubuntu 16.04). I am seeing behavior from READ-SEQUENCE which is surprising to me. Is the following conforming to the CLHS? EDIT: Franz, Inc. confirms that this is a bug. See the PS for more info.
In this example, twobytes.txt
is a file which contains a
followed by a newline.
$ /usr/local/acl11.0express.64/alisp
International Allegro CL Free Express Edition
11.0 [64-bit Linux (x86-64)]
Copyright (C) 1985-2023, Franz Inc., Lafayette, CA, USA. All Rights Reserved.
This development copy of Allegro CL is licensed to:
Allegro CL 11.0 Express user
;; Optimization settings: safety 1, space 1, speed 1, debug 2,
;; compilation-speed 1.
;; For a complete description of all compiler switches given the
;; current optimization settings evaluate (EXPLAIN-COMPILER-SETTINGS).
CL-USER(1): (defvar f (open "twobytes.txt" :element-type '(unsigned-byte 8)))
; Autoloading for EXCL::GRAY-OPEN:
; Fast loading from bundle code/streamc.fasl.
; Fast loading from bundle code/efft-utf-8s-base.fasl.
; Fast loading from bundle code/efft-utf8-base.fasl.
; Fast loading from bundle code/efft-void.fasl.
; Fast loading from bundle code/efft-latin1-base.fasl.
F
CL-USER(2): (defvar l (list 1 1 1 1 1 1))
L
CL-USER(3): (read-sequence l f)
6
CL-USER(4): l
(97 10 :EOF :EOF :EOF :EOF)
Is this a bug? I expected the return value of READ-SEQUENCE to be 2 instead of 6, and I expected L to be (97 10 1 1 1 1)
afterwards.
When I try the same code with SBCL or Clozure CL, I get the expected results.
For the record, CLHS says
If the end of file for stream is reached before copying all elements of the subsequence, then the extra elements near the end of sequence are not updated.
I looked for a list of known bugs for Allegro CL, but I was unable to find any such list.
PS. I submitted a bug report to Franz, Inc. and a representative confirms that it's a bug in the implementation of Gray streams. The workaround that was suggested is to omit :element-type
, then OPEN will return a FILE-SIMPLE-STREAM, which, fortuitously, has :element-type
equal to (unsigned-byte 8)
, and the READ-SEQUENCE bug is not present. Here is the same example as before, this time with expected behavior.
CL-USER(1): (defvar f (open "twobytes.txt"))
F
CL-USER(2): f
#<FILE-SIMPLE-STREAM #P"twobytes.txt" for input pos 0 @ #x100079bfd22>
CL-USER(3): (defvar l (list 1 1 1 1 1 1))
L
CL-USER(4): (read-sequence l f)
2
CL-USER(5): l
(97 10 1 1 1 1)
You are calling open
with an element type, which isn't a character, but an unsigned byte.
This causes in Allegro CL the autoloading of some Gray Streams functionality (see your output). Gray Streams are an old specification for CLOS based stream implementation. Then the Common Lisp system will use CLOS based stream functions like stream-read-sequence
and stream-read-byte
to read from streams. These functions have different (simplified) argument and return values, compared to the standard functions read-sequence
and read-byte
.
So, for Allegro CL:
OPEN
on a file with unsigned byte creates a Gray Stream object.
READ-SEQUENCE
then calls EXCL:STREAM-READ-SEQUENCE
, which creates this observed result
CLOS Streams
In LispWorks 8 I can use the CLOS generic function STREAM:STREAM-READ-SEQUENCE
for a file /tmp/a.txt
with two characters:
CL-USER 29 > (let ((seq (list 1 1 1 1 1 1 1 1)))
(with-open-file (s "/tmp/a.txt"
:element-type '(unsigned-byte 8))
(values (stream:stream-read-sequence
s seq 0 (length seq))
seq)))
2
(97 10 1 1 1 1 1 1)
Now, what would happen if one uses EXCL:STREAM-READ-SEQUENCE
in Allegro CL?
It puts :eof
into the list, so I suspect that its implementation fails to detect the possible :eof
value of excl:stream-read-byte
.
Allegro CL:
CG-USER(7): (let ((seq (list 1 1 1 1 1 1 1 1)))
(with-open-file (s "/tmp/a.txt"
:element-type '(unsigned-byte 8))
(values (excl:stream-read-sequence s seq 0 (length seq))
seq)))
8
(97 10 :EOF :EOF :EOF :EOF :EOF :EOF)
and if we don't specify the element type, we get this result:
CG-USER(9): (let ((seq (list 1 1 1 1 1 1 1 1)))
(with-open-file (s "/tmp/a.txt")
(values (read-sequence seq s)
seq)))
2
(97 10 1 1 1 1 1 1)
Interestingly enough, this opens the stream as with element type unsigned-byte 8.