0

I'm noticing some inconsistency in the output of this code in Clisp:

(defvar str "Another")
(setf (char str 3) #\!)

When I run it from the repl, I get the desired result:

[1]> (defvar str "Another")
STR
[2]> (setf (char str 3) #\!)
#\!
[3]> str
"Ano!her"
[4]>

However, when I run it from a script, I get a warning about modifying a readonly string:

*** - Attempt to modify a read-only string: "Another"

I got that error when running this code:

(print (do ((str "foobar")
            (i 0 (+ i 1)))
           ((= i (length str)) str)
         (setf (char str i) #\!)))

What's the point of making the string read-only(I'm assuming this is the same as immutable) when the binding will dissappear when the block ends?

And, why the discrepancy between the two outputs?

Lastly, is there a way to turn it off? I don't find the warning particularly useful.

4

1 回答 1

3

解决方案

首先,你看到的是一个error,而不是一个warning

其次,您不能将其关闭,但您可以通过复制不可变字符串来避免它:

(print (do ((str (copy-seq "foobar"))
            (i 0 (+ i 1)))
           ((= i (length str)) str)
         (setf (char str i) #\!)))

动机

为什么某些数据是不可变的,这是网络上讨论最多的话题。

基本原因是:

  • 多线程环境中的安全性和
  • 更好的编译器

理由

根据手册

尝试修改只读数据会发出错误信号。从文件加载的程序文本和引用的常量被视为只读数据。此检查仅针对字符串执行,而不针对 conses、其他类型的数组和用户定义的数据类型。

这是ANSI CL 规范明确允许的:

不需要实现来检测修改不可变对象或单元格的尝试;尝试进行此类修改的后果是不确定的

于 2013-11-14T16:13:45.500 回答