请注意,这是否符合您的条件,但是在标准ML等功能语言中,默认情况下所有内容都是不可变的。通过通用错误ref
类型支持突变。因此,int
变量是不可变的,并且ref int
变量是int
s 的可变容器。从本质上讲,变量是数学意义上的实变量(未知但固定值),而ref
s是命令式编程意义上的“变量”-可以读写的存储单元。(我喜欢称它们为可分配对象。)
我认为问题有const
两个方面。首先,C ++缺少垃圾回收,这对于拥有非平凡的持久数据结构是必需的。const
必须有足够的深度才能具有任何意义,但是在C ++中具有完全不变的值是不切实际的。
其次,在C ++中,您需要选择加入const
而不是选择退出。但是,当您忘记const
某些内容并随后对其进行修复时,您将最终遇到@RobY答案中提到的“常量中毒”情况,其中const
更改将遍历整个代码。如果const
是默认设置,则不会发现自己具有const
追溯力。另外,必须在const
任何地方添加都会增加代码的噪音。
我怀疑随后出现的主流语言(例如Java)在很大程度上受到C和C ++的成功以及思维方式的影响。举例来说,即使使用垃圾回收,大多数语言的回收API也会采用可变的数据结构。一切都是可变的并且不变性被视为一个极端案例,这一事实充分说明了流行语言背后的命令式思维。
编辑:在考虑了greenoldman的评论之后,我意识到这const
不直接涉及数据的不变性;const
编码为方法的类型是否对实例有副作用。
可以使用突变来实现参照透明的行为。假设您有一个函数,当该函数连续被调用时返回不同的值-例如,一个函数从中读取单个字符stdin
。我们可以使用缓存/存储此函数的结果来生成参考透明的值流。流将是一个链表,该链表的节点将在您第一次尝试检索其值时调用该函数,然后将其缓存。所以,如果stdin
constains Hello, world!
,你第一次尝试检索第一个节点的值,它会读取一个char
和回报H
。之后,它将继续返回,H
而无需进一步调用以读取char
。同样,第二个节点char
将从stdin
第一次尝试检索其值时,这次将返回e
并缓存该结果。
有趣的是,您已经将本来有状态的过程变成了看似无状态的对象。但是,必须改变对象的内部状态(通过缓存结果)以实现此目的-突变是一种良性效果。CharStream
const
即使流的行为就像一个不可变的值,也无法使我们成为现实。现在,假设有一个方法Stream
接口const
,而您的所有功能都在期望中const Streams
。您CharStream
无法实现该接口!
(编辑2:显然有一个名为C ++的关键字mutable
,它使我们可以作弊CharStream
const
。但是,此漏洞破坏了const
'保证'-现在您真的不能确定某些东西不会通过其const
方法发生变化。我想不是不好,因为您必须明确要求漏洞,但是您仍然完全依赖荣誉系统。)
其次,假设您具有高阶函数-也就是说,您可以将函数作为参数传递给其他函数。const
ness是函数签名的一部分,因此您将无法将非const
函数作为参数传递给需要函数的const
函数。const
在此处盲目执行将导致失去普遍性。
最后,操作const
对象并不能保证它不会使您背后的某些外部(静态或全局)状态发生变化,因此const
的保证并不像它们最初出现的那样强大。
对我来说,尚不清楚将副作用的存在或不存在编码到类型系统中通常是一件好事。