2.9 Изменяемость

Некоторые объекты Lisp никогда не должны изменяться. Например, Lisp-выражение "aaa" возвращает строку, но вы не должны изменять ее содержимое. И некоторые объекты нельзя изменить; например, хотя вы можете создать новое число, вычислив его, Lisp не предоставляет операции для изменения значения существующего числа.

Другие объекты Lisp являются изменяемыми: безопасно изменять их значения с помощью деструктивных операций, вызывающих побочные эффекты. Например, существующий маркер можно изменить, переместив маркер так, чтобы он указывал на другое место.

Хотя числа никогда не меняются, а все маркеры являются изменяемыми, некоторые типы имеют члены, некоторые из которых изменяемы, а другие — нет. К таким типам относятся консы, векторы и строки. Например, хотя "cons" и (symbol-name 'cons) возвращают строки, которые не должны изменяться, (copy-sequence "cons") и (make-string 3 ?a) возвращают изменяемые строки, которые можно изменить с помощью последующих вызовов aset.

Изменяемый объект перестает быть изменяемым, если он является частью выражения, которое вычисляется. Например:

(let* ((x (list 0.5))
       (y (eval (list 'quote x))))
  (setcar x 1.5) ;; Программа не должна этого делать.
  y)

Хотя список (0.5) был изменяемым во время создания, его не следовало изменять с помощью setcar, потому что он был передан в eval. Обратного не происходит: объект, который не должен изменяться, никогда после этого не становится изменяемым.

Если программа пытается изменить объекты, которые не должны изменяться, результирующее поведение не определено: интерпретатор Lisp может сообщить об ошибке, или он может аварийно завершиться, или вести себя непредсказуемо по другим причинам.3

Когда аналогичные константы встречаются в частях программы, интерпретатор Lisp может экономить время или память, повторно используя существующие константы или их компоненты. Например, (eq "abc" "abc") возвращает t, если интерпретатор создает только один экземпляр строкового литерала "abc", и возвращает nil, если он создает два экземпляра. Программы Lisp должны быть написаны таким образом, чтобы они работали независимо от того, используется ли эта оптимизация.


Примечания

(3)

Это поведение, указанное для таких языков, как Common Lisp и C, в отношении констант, и это отличается от таких языков, как JavaScript и Python, где требуется интерпретатор для сообщения об ошибке, если программа пытается изменить неизменяемый объект. В идеале интерпретатор Emacs Lisp будет развиваться в этом направлении.