alexandria issueshttps://gitlab.common-lisp.net/alexandria/alexandria/-/issues2024-01-31T22:59:00Zhttps://gitlab.common-lisp.net/alexandria/alexandria/-/issues/17Add Travis CI config2024-01-31T22:59:00ZStelian IonescuAdd Travis CI configAlexandria should have automatic testing, and Travis seems the most common solution. If gitlab.common-lisp.net can't provide that, the repository should be moved to Github.Alexandria should have automatic testing, and Travis seems the most common solution. If gitlab.common-lisp.net can't provide that, the repository should be moved to Github.https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/12FORMAT-SYMBOL does not accept a FORMATTER2024-01-31T09:39:53ZMichał Herdaphoe@disroot.orgFORMAT-SYMBOL does not accept a FORMATTER```lisp
CL-USER> (alexandria:format-symbol :keyword (formatter "~A~A") "FOO" "BAR")
Error: #<FUNCTION "fmt$~A~A" {52DB3B8B}> is not a string designator.
[Condition of type SIMPLE-TYPE-ERROR]
```
I claim that a formatter should be ac...```lisp
CL-USER> (alexandria:format-symbol :keyword (formatter "~A~A") "FOO" "BAR")
Error: #<FUNCTION "fmt$~A~A" {52DB3B8B}> is not a string designator.
[Condition of type SIMPLE-TYPE-ERROR]
```
I claim that a formatter should be accepted in order to preserve the semantics of `FORMAT`.
The simple fix is to remove the `STRING` call inside the body of `FORMAT-SYMBOL`.https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/44Broken test for IOTA2024-01-31T09:22:22ZAlexander FedorovBroken test for IOTASee this commit: https://gitlab.common-lisp.net/alexandria/alexandria/-/commit/1e5b8e8f5392fcb025747b7ae54045517f23e074
Test `iota.fp-start-and-complex-integer-step` was designed to test that calling `iota` with the (real) float start a...See this commit: https://gitlab.common-lisp.net/alexandria/alexandria/-/commit/1e5b8e8f5392fcb025747b7ae54045517f23e074
Test `iota.fp-start-and-complex-integer-step` was designed to test that calling `iota` with the (real) float start and complex (integer) step resulted a sequence of complex numbers. It was then incorrectly fixed because it was failing on CLISP.
I believe that test was failing because of CLISP bug, not because it was broken.
`iota` uses a somewhat kludgy hack for returning a correct type as its first element: `(+ (- (+ start step) step)` as the first element in sequence.
This doesn't work on CLISP because of the following behavior:
```lisp
(+ 0.0 #C(0 2)) ; => #C(0.0 2)
```
Note the imagpart being `2` and not `2.0`.
Per https://www.lispworks.com/documentation/HyperSpec/Body/t_comple.htm
> The real part and imaginary part are either both rational or both of the same float type.
But on CLISP (including when running with `-ansi` flag):
```lisp
(complexp (complex 2.0 2)) ; => T
(type-of (realpart (complex 2.0 2))) ; => SINGLE-FLOAT
(type-of (imagpart (complex 2.0 2))) ; => (INTEGER 0 281474976710655)
```https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/43Faster WHICHEVER2024-01-30T07:53:30ZAlexander FedorovFaster WHICHEVERCurrently `whichever` builds an inline binary search tree with O(log n) complexity. Some implementations (for example sbcl) can optimize `case` with clauses being consecutive integers, which would allow for O(1) complexity.
While alexan...Currently `whichever` builds an inline binary search tree with O(log n) complexity. Some implementations (for example sbcl) can optimize `case` with clauses being consecutive integers, which would allow for O(1) complexity.
While alexandria's goal is to be portable, that doesn't mean that it should ignore possible implementation-specific optimizations. There already exists implementation-specific code: see `alexandria:emptyp`, `alexandria:simple-reader-error` or `alexandria::default-element-type` in `io.lisp`.https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/42COMPOSE and its variants are probably unsafe2024-01-28T10:49:46ZTim BradshawCOMPOSE and its variants are probably unsafe[`COMPOSE`](https://gitlab.common-lisp.net/alexandria/alexandria/-/blob/009b7e532071d9777bdbd63b82d776555da95916/alexandria-1/functions.lisp#L58) includes this expression:
```
(lambda (&rest arguments)
(declare (dynamic-extent argumen...[`COMPOSE`](https://gitlab.common-lisp.net/alexandria/alexandria/-/blob/009b7e532071d9777bdbd63b82d776555da95916/alexandria-1/functions.lisp#L58) includes this expression:
```
(lambda (&rest arguments)
(declare (dynamic-extent arguments))
(funcall f (apply g arguments)))))
```
where `f` and `g` are unknown functions.
I think this is not safe, because
> When the function receives its arguments via &rest, it is permissible (but not required) for the implementation to bind the rest parameter to an object that shares structure with the last argument to apply.
>
> [CLHS](https://www.lispworks.com/documentation/HyperSpec/Body/f_apply.htm)
So if `g` takes an `&rest` list this may share structure with `arguments`. But a perfectly legitimate definition of `g` would be
```
(lambda (&rest args) args)
```
which could then return the list of arguments outside its dynamic extent.
I am not aware of implementations which have this behaviour for `apply`, however.https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/10if-let* would be nice2024-01-26T17:10:59ZMatthew Kraussif-let* would be niceI could use an `if-let*` macro. Wondering why there wasn't one already, I found that somebody tried to contribute it back in 2012, there was some question as to what should be bound in the else form, and then it seemed to die (https://ww...I could use an `if-let*` macro. Wondering why there wasn't one already, I found that somebody tried to contribute it back in 2012, there was some question as to what should be bound in the else form, and then it seemed to die (https://www.mail-archive.com/alexandria-devel@common-lisp.net/msg00493.html)
I could make a pull request for this, but before I do, wanted to check if there is some reason it hasn't been done...https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/34Tests TYPE=.2 and ALEXANDRIA/TESTS::TYPE=.3 fail on ABCL2024-01-25T17:40:40ZRobert GoldmanTests TYPE=.2 and ALEXANDRIA/TESTS::TYPE=.3 fail on ABCLAlexandria expects more certainty from ABCL's `subtypep` than it provides:
```
CL-USER(13): (subtypep 'list '(or null cons))
NIL
NIL
```
This one
```
CL-USER(15): (subtypep '(and symbol list) 'null)
NIL
NIL
```
If these are bugs, th...Alexandria expects more certainty from ABCL's `subtypep` than it provides:
```
CL-USER(13): (subtypep 'list '(or null cons))
NIL
NIL
```
This one
```
CL-USER(15): (subtypep '(and symbol list) 'null)
NIL
NIL
```
If these are bugs, they are probably forgivable: ABCL admits it doesn't know if its answer is correct, which I believe to be correct behavior according to the spec.
There seems to be a bug in the way Alexandria combines two `subtypep` checks into a `test=` check, because we see this:
```
CL-USER(13): (subtypep 'list '(or null cons))
NIL
NIL
CL-USER(17): (alexandria:type= 'list '(or null cons))
NIL
T
CL-USER(18): (subtypep '(or null cons) 'list)
T
T
```
Alexandria has made certainty out of uncertainty. See #35https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/26TYPE= tests might be overzealous2024-01-25T17:40:02ZMichał Herdaphoe@disroot.orgTYPE= tests might be overzealousIt seems that it's possible for an implementation to return the following (see [this thread](https://github.com/armedbear/abcl/issues/433)):
```
CL-USER(3): (subtypep '(or null cons) 'list)
T
T
CL-USER(4): (subtypep 'list '(or null cons...It seems that it's possible for an implementation to return the following (see [this thread](https://github.com/armedbear/abcl/issues/433)):
```
CL-USER(3): (subtypep '(or null cons) 'list)
T
T
CL-USER(4): (subtypep 'list '(or null cons))
NIL
NIL
CL-USER(5): (subtypep 'null '(and symbol list))
T
T
CL-USER(6): (subtypep '(and symbol list) 'null)
NIL
NIL
```
It seems that the tests for `TYPE=` do not take this into account and therefore they fail on ABCL.https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/41hash-tables keys and values should be in order, like maphash2023-12-03T10:51:12Zxi zanghash-tables keys and values should be in order, like maphash```lisp
(defun hash-table-keys (table)
"Returns a list containing the keys of hash table TABLE."
(let ((keys nil))
(maphash-keys (lambda (k)
(push k keys))
table)
(nreverse keys)))
(defu...```lisp
(defun hash-table-keys (table)
"Returns a list containing the keys of hash table TABLE."
(let ((keys nil))
(maphash-keys (lambda (k)
(push k keys))
table)
(nreverse keys)))
(defun hash-table-values (table)
"Returns a list containing the values of hash table TABLE."
(let ((values nil))
(maphash-values (lambda (v)
(push v values))
table)
(nreverse values)))
(defun hash-table-alist (table)
"Returns an association list containing the keys and values of hash table
TABLE."
(let ((alist nil))
(maphash (lambda (k v)
(push (cons k v) alist))
table)
(nreverse alist)))
(defun hash-table-plist (table)
"Returns a property list containing the keys and values of hash table
TABLE."
(let ((plist nil))
(maphash (lambda (k v)
(push k plist)
(push v plist))
table)
(nreverse plist)))
```https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/35Bug in `type=`: second value computed incorrectly2023-10-18T11:36:01ZRobert GoldmanBug in `type=`: second value computed incorrectlySee [definition of type=](https://gitlab.common-lisp.net/alexandria/alexandria/-/blob/master/alexandria-1/types.lisp#L121):
``` lisp
(defun type= (type1 type2)
"Returns a primary value of T is TYPE1 and TYPE2 are the same type,
and a ...See [definition of type=](https://gitlab.common-lisp.net/alexandria/alexandria/-/blob/master/alexandria-1/types.lisp#L121):
``` lisp
(defun type= (type1 type2)
"Returns a primary value of T is TYPE1 and TYPE2 are the same type,
and a secondary value that is true is the type equality could be reliably
determined: primary value of NIL and secondary value of T indicates that the
types are not equivalent."
(multiple-value-bind (sub ok) (subtypep type1 type2)
(cond ((and ok sub)
(subtypep type2 type1))
(ok
(values nil ok))
(t
(multiple-value-bind (sub ok) (subtypep type2 type1)
(declare (ignore sub))
(values nil ok))))))
```
In the case where the first return is `(NIL NIL)` and the second is `(T T)`, this will return `(NIL T)`, which is incorrect -- we are not certain that the two types are unequal.
If the second value is `(NIL T)` then we should return `(NIL T)`, otherwise we should return `(NIL NIL)` since both results are uncertain.
See #34 for an example.https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/27DECLARE the hash table utils INLINE2023-10-17T22:08:49ZMichał Herdaphoe@disroot.orgDECLARE the hash table utils INLINEhttps://gitlab.common-lisp.net/alexandria/alexandria/-/blob/9acc5bd5064d941bc0929d14aca82225aefb464c/alexandria-1/hash-tables.lisp#L52-101
`hash-table{keys,values}`, `{alist,plist}-hash-table` and `hash-table-{alist,plist}` can be decla...https://gitlab.common-lisp.net/alexandria/alexandria/-/blob/9acc5bd5064d941bc0929d14aca82225aefb464c/alexandria-1/hash-tables.lisp#L52-101
`hash-table{keys,values}`, `{alist,plist}-hash-table` and `hash-table-{alist,plist}` can be declared `inline`, I think - is there a reason why only `maphash-{keys,values}` are made so right now?https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/39SWITCH with default-only clause emits a warning2023-10-17T14:25:23ZAlexander FedorovSWITCH with default-only clause emits a warningEmits a warning that can't be avoided.
```lisp
* (alexandria:switch (t)
(t))
; in: A:SWITCH (T)
; (#:VALUE200 (IDENTITY T))
;
; caught STYLE-WARNING:
; The variable #:VALUE200 is defined but never used.
;
; compilation unit f...Emits a warning that can't be avoided.
```lisp
* (alexandria:switch (t)
(t))
; in: A:SWITCH (T)
; (#:VALUE200 (IDENTITY T))
;
; caught STYLE-WARNING:
; The variable #:VALUE200 is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
NIL
```
The internal variable should probably be declared `ignorable`.https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/37Test CURRY.3 broken on CMUCL2023-10-17T13:48:26ZRobert GoldmanTest CURRY.3 broken on CMUCLThis one I'm afraid I cannot debug or fix: I have an M1 Mac and cannot run CMUCL (which is 32-bit only). Someone should fix this or disable the tests on CMUCL.This one I'm afraid I cannot debug or fix: I have an M1 Mac and cannot run CMUCL (which is 32-bit only). Someone should fix this or disable the tests on CMUCL.https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/20Make (R)CURRY globally INLINE to allow expansion of compiler macros2023-10-17T12:49:56ZPhoebe GoldmanMake (R)CURRY globally INLINE to allow expansion of compiler macrosAt present, `curry` and `rcurry` have preceding `inline` declarations which allow the collection of inlining information, and they have compiler macros, but both are globally disabled. In the absence of any documentation describing why i...At present, `curry` and `rcurry` have preceding `inline` declarations which allow the collection of inlining information, and they have compiler macros, but both are globally disabled. In the absence of any documentation describing why it would be beneficial not to inline these forms or to expand these compiler macros, I assume there is no good reason. SBCL has been issuing compiler notes at me every time I invoke `curry` or `rcurry` because it must emit typechecks that the result will be a function, and I would very much prefer not to start every source file of mine with `(declaim (inline curry rcurry))`. So, unless there's a good reason not to, please remove the `notinline` declaration for `curry` and `rcurry` at line 155 of functions.lisp and let the compiler macros do their job. Thanks!https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/40Feature request: PARSE-BODY configurable behaviour when duplicate doc strings...2023-10-17T12:14:53ZAlexander FedorovFeature request: PARSE-BODY configurable behaviour when duplicate doc strings occurIt would be nice if it was possible to parse bodies with duplicate doc-strings.
It could be provided as an additional keyword argument that would take options like `:error` [default one as it is current behaviour], `:warn`, `:ignore`, `...It would be nice if it was possible to parse bodies with duplicate doc-strings.
It could be provided as an additional keyword argument that would take options like `:error` [default one as it is current behaviour], `:warn`, `:ignore`, `:override` [this one to take the latest doc-string instead of the first one]
Another option would be to signal a continuable error instead of just error with restarts like `ignore` and `override`.
[ I am pretty sure that "override" is not the right name here, but I don't know how to name that instead ]
To add a bit of context:
CLHS 3.4.11 says "The consequences are unspecified if more than one such documentation string is present."
To understand possible behavior I tried the following code on multiple implementations:
```lisp
(defun abcd () "a" "b" "c" "d")
(documentation 'abcd 'function)
```
Here are the results:
Implementations can
* Silently use the first string (`"a"`) as the documentation string.
CMUCL [21e], Allegro CL [FEE 10.1], ECL [21.2.1], ABCL [1.9.1], LispWorks [PE 8.0.1]
* Warn about the the first duplicate doc string (`"b"`) and uses the first one (`"a"`) as the documentation string.
SBCL [2.3.9]
* Silently use the last string (`"c"`) as the documentation string.
CCL [1.12], CLASP [2.2.0]
* Signal an uncontinuable error.
CLISP [2.49.93]https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/38tests broken on SBCL2023-10-16T01:32:21ZHraban Luyattests broken on SBCLTests are broken on SBCL since !30 because of hard-coded test package name (rt vs sb-rt).Tests are broken on SBCL since !30 because of hard-coded test package name (rt vs sb-rt).https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/30COPY-HASH-TABLE EQ test fails on Allegro CL v 11 beta: Allegro result seems a...2023-05-03T14:51:29ZRobert GoldmanCOPY-HASH-TABLE EQ test fails on Allegro CL v 11 beta: Allegro result seems acceptable by specInvestigating in the REPL I see this:
```
ALEXANDRIA/TESTS> (multiple-value-setq (orig eq-copy)
(let ((orig (make-hash-table :test 'eq :size 123))
(foo "foo"))
(setf (g...Investigating in the REPL I see this:
```
ALEXANDRIA/TESTS> (multiple-value-setq (orig eq-copy)
(let ((orig (make-hash-table :test 'eq :size 123))
(foo "foo"))
(setf (gethash orig orig) t
(gethash foo orig) t)
(let ((eq-copy (copy-hash-table orig)))
(values orig eq-copy))))
#<EQ hash-table with 2 entries @ #x3078a3982>
ALEXANDRIA/TESTS> orig
#<EQ hash-table with 2 entries @ #x307a26422>
ALEXANDRIA/TESTS> eq-copy
#<EQ hash-table with 2 entries @ #x307816892>
ALEXANDRIA/TESTS> (hash-table-size orig)
191 (8 bits, #xbf, #o277, #b10111111)
ALEXANDRIA/TESTS> (hash-table-size eq-copy)
307 (9 bits, #x133)
```
Looking at the Spec, it doesn't seem like we are entitled to assume that a copy will have the same size -- the size is not the number of entries, and it seems to be under the implementation's control. At least that's how I read the following:
> Returns the current size of hash-table, which is suitable for use in a call to make-hash-table in order to produce a hash table with state corresponding to the current state of the hash-table.
I will submit a patch, together with my patch for #29 that disables this test on Allegro.https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/31read-stream-content-into-byte-vector.2 fails on Allegro Beta 11: Unsure if Al...2023-05-03T14:33:30ZRobert Goldmanread-stream-content-into-byte-vector.2 fails on Allegro Beta 11: Unsure if Allegro result is acceptableThis test fails because the test expects a `type-error`, but Allegro raises a `:program-error`.
I'd appreciate it if someone could let me know if this is something that can be fixed in the test, or if it is a bug in the Allegro implemen...This test fails because the test expects a `type-error`, but Allegro raises a `:program-error`.
I'd appreciate it if someone could let me know if this is something that can be fixed in the test, or if it is a bug in the Allegro implementation. It seems like it *should* be a `type-error`, but does the spec *dictate* that it's a `type-error`? If so, I can report it to Franz; if not, I will move to checking for a `program-error` on Allegro (in my MR for #29, to come).https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/32TYPE=.4 test fails on Allegro Beta 11: Allegro result seems consistent with spec2023-05-03T14:31:05ZRobert GoldmanTYPE=.4 test fails on Allegro Beta 11: Allegro result seems consistent with specThis test expects a return of `(nil nil)`, but on Allegro returns `(nil t)`. This is because on Allegro:
```
(subtypep 'string '(satisfies emptyp))
NIL
T
```
I don't think that it's wrong to return `(nil t)` from this `type=`, is it?...This test expects a return of `(nil nil)`, but on Allegro returns `(nil t)`. This is because on Allegro:
```
(subtypep 'string '(satisfies emptyp))
NIL
T
```
I don't think that it's wrong to return `(nil t)` from this `type=`, is it? I propose to modify the test to ignore the second value if you agree. This is in my fix MR !27
By the way, `type=.3` *also* fails on Allegro, but this one is a bug in Allegro, which I have reported to Franz.https://gitlab.common-lisp.net/alexandria/alexandria/-/issues/36clasp tests don't run2023-05-02T19:21:27ZRobert Goldmanclasp tests don't runThere's something wrong with the docker image. Until that is fixed, this test should be disabled.There's something wrong with the docker image. Until that is fixed, this test should be disabled.