对象的可变性

时间:2013-07-07 03:54:45

标签: scala

Martin Odersky为Scala Days 2013做了主题演讲。

一张标题为“When is an Object Mutable?”其内容如下:

class Memo[T, U](fn: T => U) {

  val memo = new mutable.WeakHashMap[T, U]
  def apply(x: T) = memo.getOrElseUpdate(x, fn(x))
}

// an object is mutable if its (functional) behavior depends on its history

new Memo {i: Int => i + 1} // immutable

var ctr = 0;
new Memo { i: Int => ctr += i; ctr } // mutable

请解释为什么备忘录示例分别是不可变和可变的。

2 个答案:

答案 0 :(得分:3)

在第一个示例中,提供的函数将给定值增加1.结果不依赖于任何外部状态。

在第二个示例中,结果取决于ctr值,该值是与Memo相关的某种全局状态。换句话说,由ctr值表示的全局状态可以影响第二个示例中的行为和结果。

答案 1 :(得分:0)

来自Wikipedia

的引用
  

在某些情况下,即使某些内部使用的属性发生更改,但对象的状态从外部角度看似不变,也会将对象视为不可变。例如,使用memoization来缓存昂贵计算结果的对象仍然可以被视为不可变对象。

但是我想提请注意“可以 [...]被考虑”,所以不是每个人都认为它是不可变的。

如果您使用不可变Map来查看此Memo实现:

class Memo[T, U](val fn: T => U, map: Map[T, U]) {
  def this(fn: T => U) {
    this(fn, Map[T, U]())
  }

  def apply(x: T): (U, Memo[T, U]) = {
    if (map.contains(x)) {
      println("Cache hit")
      (map(x), this)
    } else {
      println("Cache miss")
      val result = fn(x)
      val newMap = map + ((x, result))
      (result, new Memo(fn, newMap))
    }
  }
}

根本没有可变的内部状态(它被委托给调用者)。但现在我们有两个不可变性程度不同的问题。

从实际角度来看,memoizer必须功能,但其名称/目的意味着可变性,即使它不影响外部行为。