[Openmcl-devel] #+/#- issues
Joshua TAYLOR
tayloj at cs.rpi.edu
Tue Mar 3 18:15:07 PST 2009
Hi all,
I browsed around on the Trac for a while to see if this has already
been mentioned, but I didn't find it (though there were things that
may be related; sorry if this is already documented/known/&c.). I was
recently reading some code that conditionally passed arguments to a
function, particularly, in DRAKMA's request.lisp I came across
#-:lispworks
(usocket:socket-stream
(usocket:socket-connect host port
:element-type 'octet
#+openmcl #+openmcl ;; this is what caught my eye
:deadline deadline
:nodelay t))
Now I had never seen that sort of conditionalization before, and so
before sending any bugreports here or to Edi I asked on c.l.l [1]
whether this adhered to the standard or not. As it turns out, it seems
that the behavior there is implementation-dependent. And I can confirm
that implementations do different things. E.g., CCL 1.3 does
(list #-ccl #-ccl 1 2 3 4) => (2 3 4)
while Lispworks 5.1 does
(list #-lispworks #-lispworks 1 2 3 4) => (3 4)
I think that more people might expect the latter behavior, but I think
that from the c.l.l discussion we determined that both are
permissible, depending on whether *READ-SUPPRESS* is bound to NIL or
to T when the second feature expression is being read. In fact, if we
push NIL onto *features* we can get some interesting results too.
Again, in CCL 1.3:
(push nil *features*) => (NIL :PRIMARY-CLASSES ...)
(list #-ccl #-ccl 1 2 3 4) => (3 4)
At any rate, that's all OK. I think that the following is a bug. In
the hyperspec we read:
"2.4.8.18 Sharpsign Minus
#- is like #+ except that it skips the expression if the test succeeds; that is,
#-test expression == #+(not test) expression"
But look what CCL does:
CL-USER> (list #-ccl #-ccl 1 2 3 4)
(2 3 4)
CL-USER> (list #-ccl #+(not ccl) 1 2 3 4)
(3 4)
CL-USER> (list #+(not ccl) #-ccl 1 2 3 4)
(2 3 4)
CL-USER> (list #+(not ccl) #+(not ccl) 1 2 3 4)
(3 4)
(Another interesting case is that (list #-ccl #+(not ccl) 2) returns
NIL, but (list #-ccl #-ccl 2) signals an error.)
Clearly #-ccl =/= #+(not ccl) in these examples. It seems that binding
*READ-SUPPRESS* to NIL during READ-FEATURE would get the behavior that
some people are expecting, and would make #-test and #+(not test)
behave equivalently. In l1-reader.lisp, that would be:
(defun read-feature (stream)
(let* ((f (let* ((*package* *keyword-package*)
(*read-suppress* nil)) ; <== The added binding
(read stream t nil t))))
(labels ((eval-feature (form)
(cond ((atom form)
(member form *features*))
((eq (car form) :not)
(not (eval-feature (cadr form))))
((eq (car form) :and)
(dolist (subform (cdr form) t)
(unless (eval-feature subform) (return))))
((eq (car form) :or)
(dolist (subform (cdr form) nil)
(when (eval-feature subform) (return t))))
(t (%err-disp $XRDFEATURE form)))))
(if (eval-feature f) #\+ #\-))))
Thanks all for a great Lisp! This is the only 'bug' I've run into so
far, and it hasn't even caused any problems for me yet. (But I were to
put NIL in *FEATURES*…)
//JT
[1] http://groups.google.com/group/comp.lang.lisp/browse_thread/thread/8d50284a29f51673#
--
=====================
Joshua Taylor
tayloj at cs.rpi.edu, jtaylor at alum.rpi.edu
"A lot of good things went down one time,
back in the goodle days."
John Hartford
More information about the Openmcl-devel
mailing list