Destructuring-bind of (&REST foo) might not be ansi-compliant
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
New
|
Undecided
|
Unassigned |
Bug Description
The spec is unclear about the meaning of
(DESTRUCTURING
It seems that the actual argument to the above DESTRUCTURING-BIND needn't be a list because the tail of the input should be delivered into FOO (in general after popping any preceding parts, of which there are none in the example).
At least 5 different implementations take the &REST to mean effectively
(LET ((FOO ARG)) ...)
and 3 of those 5 agree that this extends to nested patterns, whereas SBCL enforces list-ness in all situations.
I see two points in favor of an interpretation that FOO binds to ARG with no restriction that it satisfy LISTP:
1. (LIST* x) == x for any atom, which is a similar boundary case.
2. In the backquoted form `(,@L) it looks as if L must be a list, but instead there is de-facto agreement by most implementations that L can be an atom.
The only point in favor of enforcing (LISTP ARG) seems to be that "surely" the parentheses mean that it is a list.
So suppose F and G are defined thusly:
(defun f (args) (destructuring-bind (&rest a) args a))
(defun g (args) (destructuring-bind ((&rest a) &rest b) args (values a b)))
CCL, ECL, CLISP produce the following values:
(f 1) => 1
(g '(1 2)) => 1 and (2)
But in CMUCL:
(f 1) => 1 but (g '(1 2)) signals an error
And in ABCL
(f 1) => 1 but (g '(1 2)) encounters a system error trying to signal the user error. (i.e. The implementation is itself buggy)
SBCL signals an error for both calls.
Ironically http://
"Also, there's no reason to unnecessarily restrict &REST since there is no computational overhead and since there's no dispute about how to interpret programmer intent in this gray area."