Does SBCL change the EQness of a local object of a related function, although it is not set?

Given this code example (from the Reddit / r / lisp question ):

(defun next (pos) (nth (1+ pos) '(0 1 2 3 4 5 6 7 8 9 10))) (defvar *next* (function next)) (let ((old-next #'next) (previous (make-hash-table))) (format t "~% 1 EQ? ~a" (eq old-next *next*)) (defun next (pos) (or (gethash pos previous) (setf (gethash pos previous) (funcall old-next pos)))) (format t "~% 2 EQ? ~a" (eq old-next *next*))) 

The NEXT function is set above. Inside LET we store the old function in OLD-NEXT . Then we will redefine the global function NEXT inside LET .

BKK / CMUCL / VKT / ECL / CLISP / LispWorks / ABCL:

 ? (load "test.lisp") 1 EQ? T 2 EQ? T 

Only SBCL (SBCL 1.3.11) has a different result:

 * (load "test.lisp") 1 EQ? T 2 EQ? NIL 

The value of the local variable OLD-NEXT no longer eq for the value of the global variable *next* .

Why???

+7
common-lisp sbcl ansi-common-lisp
source share
2 answers

It seems that SBCL is trying to be smart and optimizing the variable.

 (defun foobar () (print :foo)) (let ((old #'foobar)) (funcall old) (defun foobar () (print :bar)) (funcall old)) 

Print

 :FOO :BAR 

But if you use SETF for a variable,

 (defun foobar () (print :foo)) (let ((old #'foobar)) (funcall old) (setf old #'foobar) (defun foobar () (print :bar)) (funcall old)) 

he prints

 :FOO :FOO 
+2
source share

The behavior changes whether the variables are special:

 (inspect (progn (defun next ()) (let ((old #'next) (foo #'next)) (declare (special foo)) (defun next () :different) (list old foo)))) The object is a proper list of length 2. 0. 0: #<FUNCTION NEXT> 1. 1: #<FUNCTION NEXT {10037694EB}> 

The first element refers to the most recent definition, while the second, derived from a special variable, is the old definition, as expected. When you delete a special ad, both links are EQ (and indicate a new definition).

+2
source share

All Articles