This is a bug in sbcl?

孤街浪徒 提交于 2019-12-10 05:32:15

问题


Why happen this in sbcl? Maybe a bug?

(defclass myclass ()
  ((s1
    :initform '((a . 1) (b . 2))) 
   (s2
    :initform '((a . 1) (b . 2)))))

(defparameter ins (make-instance 'myclass))

(setf (cdr (assoc 'a (slot-value ins 's1))) 43) ;; change only slot s1

;; here my problem

(slot-value ins 's1)  ;; => ((a . 44) (b . 2)))
(slot-value ins 's2)  ;; => ((a . 44) (b . 2)))

But if change :initform to :

(defclass myclass ()
  ((s1
    :initform '((a . 1) (b . 2))) 
   (s2
    :initform '((a . 1) (b . 3)))))

The problem disappears

I test this in sbcl 1.4.3 and 1.4.11. In clisp it seems that the problem does not arise.


回答1:


No. You are modifying literal data, which has undefined consequences.

When you quote a list in source code, it means that the thing you want to work with is exactly the list that the reader produced from your source code—this is a literal list. Such things may be remembered by the reader so that two identical lists are not duplicated.

One way to fix this is to create the lists at runtime, using list and cons:

(defclass myclass ()
  ((s1
    :initform (list (cons a 1) (cons b 2))) 
   (s2
    :initform (list (cons a 1) (cons b 2)))))



回答2:


This is not a bug. '((a . 1) (b . 2)) is a literal constant and as all constants assumed immutable. That means all occurrences of '(a . 1) that also are literal can just point to the car of the other one since it should never change

Now implementations can choose to make new structures so CLISP might do that, but you cannot rely on this. You should not mutate literal data.

If you are going to change it you need to use a deep copy, like this:

(defclass myclass ()
  ((s1
    :initform (copy-tree '((a . 1) (b . 2)))) 
   (s2
    :initform (copy-tree '((a . 1) (b . 2))))))


来源:https://stackoverflow.com/questions/52086082/this-is-a-bug-in-sbcl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!