(lambda (&rest arguments)
(declare (dynamic-extent arguments))
(funcall f (apply (lambda (&rest args) args) arguments)))))
If the inner lambda
merely returns args
(which shares structure with arguments
) then f
receives something that possibly shares structure with arguments
, which is fine, because the extent of arguments
ends within the dynamic scope of the outside lambda
, and f
is called within that scope.
If anything, f
needs to be careful also to not look like (lambda (x) x)
, because that is leaking the arguments
outside; I've never seen a use of compose
like this, though, since it would effectively turn (compose (lambda (x) args) (lambda (&rest x) x)
into a very expensive and dangerous list
call.
In particular, on SBCL, this seems to work:
CL-USER> (let ((ht (make-hash-table)))
(loop for i from 1 to 100 do (setf (gethash i ht) i))
(loop for x being the hash-value of ht collect x))
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100)
But on i.e. CCL this falls apart immediately:
Clozure Common Lisp Version 1.12 (v1.12) LinuxX8664
For more information about CCL, please see http://ccl.clozure.com.
CCL is free software. It is distributed under the terms of the Apache
Licence, Version 2.0.
? (let ((ht (make-hash-table)))
(loop for i from 1 to 100 do (setf (gethash i ht) i))
(loop for x being the hash-value of ht collect x))
(19 1 20 66 53 76 35 2 42 69 11 41 95 83 63 4 30 39 89 22 90 27 80 45 32 29 86 31 46 72 55 96 93 78 48 98 56 88 75 17 74 65 10 3 60 61 77 54 25 62 79 82 70 8 13 67 21 59 94 38 58 15 23 51 16 33 91 28 5 36 99 24 52 44 43 40 100 12 34 92 64 14 26 18 47 37 81 6 84 7 68 57 73 97 9 87 50 49 85 71)
Both behaviors are conforming.
Hashtables have no internal order, though. MAPHASH
provides no guarantees about the order in which entries of that hashtable will be processed.
Merged https://github.com/cffi/cffi/pull/361 as a workaround in CFFI.
Remove the ALEXANDRIA:
prefix.
The reader conditionalizing and explicitly prefixing the symbol in ALEXANDRIA:
is unnecessary. Package locks are only triggered if the current package is not ALEXANDRIA
; you should be able to just (DEFSETF ENSURE-GETHASH ...)
ASDF 3.3.6.
(uiop:define-package #:foo
(:use #:cl)
(:import-from #:alexandria "DEFINE-CONSTANT"))
The value
"DEFINE-CONSTANT"
is not of type
SYMBOL
[Condition of type TYPE-ERROR]
I guess that strings not being accepted in DEFINE-PACKAGE
is a bug since DEFINE-PACKAGE
is meant to be a drop-in replacement for DEFPACKAGE
; it's just possible that no one reported that bug because using strings in package designators is kind of a thing of the past whereas DEFINE-PACKAGE
is a thing of the future.
Did I get it right, or did strings get explicitly dropped from DEFINE-PACKAGE
, at which point it should be documented somewhere?
The system description says:
(let ((VAR NIL))
(unwind-protect
(progn
(setf VAR (ENTER CONTEXT-ITEM))
(handler-case
CODE
(error (e)
(HANDLE VAR e))
))
(EXIT VAR)))
In the above case, there is no way to choose not to handle the condition and let it propagate up the stack, since HANDLER-CASE
will always transfer control to the HANDLE
function; in addition, non-error conditions cannot be handled.
Is it possible to specify which types of conditions should be handled and whether or not the handling should perform a non-local jump, e.g. via a boolean value of the HANDLE
function?
Is it possible to modify the algorithm used by UIOP:DEFINE-PACKAGE
:MIX
option to handle explicit :IMPORT-FROM
s in a meaningful manner?
Reason: I have attempted to define a package which mixes my own package with Closer MOP's CLOSER-COMMON-LISP
package, but the package CLOSER-COMMON-LISP
uses explicit :IMPORT-FROM
s in https://github.com/pcostanza/closer-mop/blob/master/closer-mop-packages.lisp#L269.
The smallest reproducible case I've found is (DEFINE-PACKAGE #:FOO (:MIX :C2CL))
.
It should be a backwards-compatible change, since the current behavior is to signal a compile-time error.
PEBKAC, forgot a (:USE)
. Without it, the call was actually (DEFINE-PACKAGE #:FOO (:USE :COMMON-LISP) (:MIX :C2CL))
, which makes obvious conflicts. Apologies for the noise.
Is it possible to modify the algorithm used by UIOP:DEFINE-PACKAGE
:MIX
option to handle explicit :IMPORT-FROM
s in a meaningful manner?
Reason: I have attempted to define a package which mixes my own package with Closer MOP's CLOSER-COMMON-LISP
package, but the package CLOSER-COMMON-LISP
uses explicit :IMPORT-FROM
s in https://github.com/pcostanza/closer-mop/blob/master/closer-mop-packages.lisp#L269.
The smallest reproducible case I've found is (DEFINE-PACKAGE #:FOO (:MIX :C2CL))
.
It should be a backwards-compatible change, since the current behavior is to signal a compile-time error.
The main problem I see is in your last bullet - in order to be able to pass the encoding, we'd need to support encodings, which means that Alexandria must depend on Babel, which means big trouble.
OTOH, the user already needs to know whether the results are characters or octets... most likely the code afterwards needs to handle that differently.
The user probably knows this already - the stream is either a character stream (which is the base case) or a byte stream (at which point the implementation is going to implicitly perform the conversion). In this case, there's a byte stream whose contents are supposed to be read into a string and the user explicitly knows this and the implementation explicitly permits for this as a language extension.
I think we can let the implementation do their thing and change Alexandria to not get in the way. What do you think?
Let me repost a conversation from alexandria-devel
- the first email/diff outlines the problem, the rest is the follow-up discussion.
Madhu enometh@meer.net:
* alexandria-1/io.lisp: (read-stream-content-into-string): fix recent
lossage: This addresses problems in commits (13b1575, 6ff6820,
9c97e6f, on 2021-10-24), which changed the element-type of the array
used by READ-SEQUENCE to read from the stream from CHARACTER to the
STREAM-ELEMENT-TYPE of the stream.
On CCL, ECL etc. this breaks nyxt's source/start.lisp:(listen-socket)
which basically does
(iolib:with-open-socket (s :address-family :local :connect :passive :local-filename "/tmp/foo")
(alexandria:read-stream-content-into-string (iolib:accept-connection s)))
Iolib returns an octet stream for which the STREAM-ELEMENT-TYPE is not
CHARACTER. READ-STREAM-CONTENT-INTO-STRING uses WITH-OUTPUT-TO-STRING
and that calls MAKE-STRING-OUTPUT-STREAM, the argument
:ELEMENT-TYPE ((UNSIGNED-BYTE 8)) which fails because it must be a
subtype of character
The present fix is to check if it is not a character stream and force
set the element-type to 'character if it is not.
---
alexandria-1/io.lisp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/alexandria-1/io.lisp b/alexandria-1/io.lisp
index d3be536..8c93dd6 100644
--- a/alexandria-1/io.lisp
+++ b/alexandria-1/io.lisp
@@ -65,6 +65,8 @@ (defun read-stream-content-into-string (stream &key (buffer-size 4096))
(check-type buffer-size positive-integer)
(let ((*print-pretty* nil)
(element-type (stream-element-type stream)))
+ (unless (subtypep element-type 'character)
+ (setq element-type 'character))
(with-output-to-string (datum nil :element-type element-type)
(let ((buffer (make-array buffer-size :element-type element-type)))
(loop
Attila:
just a quick note: SUBTYPEP calls can be very costly.
Me:
This doesn't look like a problem on the Alexandria side. Stuffing ub8 values into any place that requires characters always requires additional information about character encoding (is it latin1? latin2? windows-1250?) and dealing with character encodings is out of scope of Alexandria. I think that Flexi Streams/Babel should be explicitly used in this context.
Madhu:
1. The function contract requires it to return a string which is of type character. 2. Arranging to call WITH-OUTPUT-TO-STRING with an octet backing it is buffer is a bug. 3. Lisps implementation support bivalent streams and alendria (correctly) deferred to the implementations behaviour, and this has been changed.
If we accept your position, READ-STREAM-CONTENT-INTO-STRING function would have to be removed from alexandia, since it cannot support it.
Me:
1. The function contract requires it to return a string which is of type character.
The function contract doesn't say anything about accepting a stream whose element type is not a character.
3. Lisps implementation support bivalent streams and alendria (correctly) deferred to the implementations behaviour, and this has been changed. The fact that implementations support bivalent streams as a language extension doesn't mean that trying to stuff octets into strings is portable Common Lisp. The third bullet in Alexandria's README (https://gitlab.common-lisp.net/alexandria/alexandria/-/blob/master/README) states that Alexandria is all about portable CL.
Still, after waking up, I am of two minds about this issue, since there's also the issue of programmer convenience, "don't break userspace", and "if an implementation supports an extension, Alexandria could at least try not to get in the way". Are you able to make an account at https://gitlab.common-lisp.net and post an issue to https://gitlab.common-lisp.net/alexandria/alexandria/-/issues? If not, I'll make it and try to ask for opinion there.
Madhu:
Hello, no I do not have a c-l.net account (and I'm not sure I want to create one now because of personal issues with gitlab---I do have a github account but that may not help).
My own opinion is of course that the previous behaviour should be supported either by reverting the changes or by biting the bitter pill (of some "non-portability"), I trust you will make a suitable decision. --Best Regards, Madhu
The question is more, like, how much of Alexandria should be inline by default, and how much of it should be inlineable by the user?
OK. What do you mean by "(nearly) everywhere"? Just the hash table utils, or more Alexandria code?
Sounds good, we'd need to instruct people that Alexandria functions are inlineable. Some sort of mention in the manual?
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?
Via https://twitter.com/RainerJoswig/status/1484711125459550216
(eval-when (:compile-toplevel :load-toplevel :execute)
;;; Clause-info structures, which are put in the clause index.
(defstruct clause-info
function
keywords
req-keywords
doc-string
generator?)
;;; Driver-info structures, for information about driver variables--used by
;;; NEXT.
(defstruct driver-info
next-code
generator?
(used nil))
;;; Previous-info structures, used by the PREVIOUS mechanism.
(defstruct previous-info
var
save-info-list
code
(class :step))
(defstruct save-info
save-var
save-vars
iv-ref)
)
Reading from a slot for which no default value was provided before that value was set is undefined behavior, and Rainer notes that this bit him on Genera. For instance, MAKE-PREVIOUS-INFO
is called like (make-previous-info :var var :class default-class)
which means that the initial values of CODE
and SAVE-INFO-LIST
are undefined. Rainer likely ends up with attempts to read from these slots somewhere from within ITERATE, and that invokes UB.
A solution is to provide explicit initialization forms for these.
It seems that it's possible for an implementation to return the following (see this thread):
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.
Top-level preservation:
(...) return-from No
(...)
Nitpick: I don't think return-from
can preserve toplevelness because a toplevel return-from
is always an error because there is no block
to return to.