Это ошибка в sbcl? - PullRequest
       40

Это ошибка в sbcl?

0 голосов
/ 30 августа 2018

Почему так происходит в sbcl? Может быть, ошибка?

(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)))

Но если изменить: initform to:

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

Проблема исчезает

Я проверяю это в sbcl 1.4.3 и 1.4.11 . В clisp кажется, что проблема не возникает.

Ответы [ 2 ]

0 голосов
/ 30 августа 2018

Это не ошибка. '((a . 1) (b . 2)) является буквальной константой и, как и все константы, предполагается неизменной. Это означает, что все вхождения '(a . 1), которые также являются буквальными, могут просто указывать на car другого, поскольку оно никогда не должно измениться

Теперь реализации могут создавать новые структуры, чтобы CLISP мог это делать, но вы не можете на это полагаться. Вы не должны видоизменять буквальные данные.

Если вы собираетесь изменить его, вам нужно использовать глубокую копию, например:

(defclass myclass ()
  ((s1
    :initform (copy-tree '((a . 1) (b . 2)))) 
   (s2
    :initform (copy-tree '((a . 1) (b . 2))))))
0 голосов
/ 30 августа 2018

Нет. Вы модифицируете литеральные данные, что имеет неопределенные последствия.

Когда вы цитируете список в исходном коде, это означает, что вы хотите работать именно с тем списком, который читатель создал из вашего исходного кода - это буквальный список. Читатель может запомнить такие вещи, чтобы два одинаковых списка не дублировались.

Один из способов исправить это - создать списки во время выполнения, используя list и cons:

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