【问题标题】:why I can update state of an Object extend immutable trait in scala为什么我可以在scala中更新对象扩展不可变特征的状态
【发布时间】:2019-01-11 02:33:51
【问题描述】:

我创建了一个扩展 scala.Immutable 的类

  class SomeThing(var string: String) extends Immutable {
      override def toString: String = string
  }

正如我所料,scala 编译器应该可以帮助我防止更改 SomeThing 类的状态。但是当我运行这个测试时

  "Test change state of immutable interface" should "not allow" in {
     val someThing = new SomeThing("hello")
     someThing.string = "hello 1"
     println(someThing)
  }

结果是hello 1,scala 编译器不会抛出任何警告或错误。

为什么他们必须添加不可变特征而不帮助我们防止对象可变?

【问题讨论】:

  • 如果你想防止变量发生突变,只需将其设为val 而不是var - 这将生成你想要的编译警告。关于scala.Immutable,我以前从未见过,但它似乎只是scala库内部使用的一个普通特征,用于区分 Immutable VS Mutable 数据结构(如集合),我不认为它打算由客户端代码使用。
  • 文档说它是一个标记特征。因此,特征的存在使得 you 可以告诉 others 该数据结构是不可变的。在你的情况下,你只是在撒谎。如果您撒谎,编译器将无能为力。请注意,编译器根本不可能检查数据结构是否不可变,事实上,这相当于解决了停机问题。
  • 我打开了一个 scala/bug 票,建议弃用该特征并最终从标准库中删除:github.com/scala/bug/issues/11353

标签: scala


【解决方案1】:

这个问题有几个方面。

1. 一个简单的原因是 Scala 编译器由于多种原因无法真正确保不变性。例如,主要目标平台 JVM 甚至允许使用反射修改 final 字段。另一个无法执行的原因是这样的代码

 /////////////////////////////////////////
 //// library v1
 package library

 class LibraryData(val value:Int)


 /////////////////////////////////////////
 //// code that uses the library
 package app

 class UserData(val data:LibraryData) extends Immutable



 /////////////////////////////////////////
 //// library v2
 package library

 class LibraryData(var value:Int) //now change it to var!

由于“库”是独立于“应用程序”编译的,甚至不知道“应用程序”的存在,因此编译器没有时间点可以捕捉到损坏的合同。

2. 你似乎有更根本的误解是trait 所做的。在这种情况下,trait(或某些其他语言中的“interface”)表示实现与用户代码之间关于实现如何以及应该如何实现的契约表现。然而,并非每种合约都可以表示为trait(至少不会使代码变得超级复杂)。例如,对于可变集合,有一个契约,size 应该返回调用 add(或 +=)的次数,但是除了声明之外,没有办法将这样的契约表示为 trait有方法 size+= 具有相应的签名。另一方面,对于大多数合同来说,没有办法强制执行以遵循合同。例如,始终返回 0size 实现在技术上匹配所有类型,但显然违反了约定。

同样Immutable doc 说:

所有不可变数据结构(例如不可变集合)的标记特征。

所以它只是一个标记trait,这是解决不能真正表示为类型的合同的方法之一。它说,谁实现了该特征声称是一个不可变的对象。您的代码声称但显然违反了合同。所以从技术上讲,不遵守合同是你的错。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-17
    • 1970-01-01
    • 2017-01-30
    • 2019-11-12
    • 2012-12-11
    • 1970-01-01
    • 2012-10-26
    相关资源
    最近更新 更多