0

Martin Odersky gave the Keynote talk for Scala Days 2013.

One slide was titled "When is an Object Mutable?" Its contents read as follow:

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

Please explain why the Memo examples are, respectively, immutable and mutable.

4

2 回答 2

3

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

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

于 2013-07-07T04:00:36.793 回答
0

来自维基百科的引述

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

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

如果您使用不可变映射查看此备忘录实现:

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 必须是函数式的,但它的名称/用途意味着可变性,即使它不影响外部行为。

于 2013-07-07T08:29:08.440 回答