开发者

Why can't a variable be a stable identifier?

The following

def mMatch(s: String) = {
    var target: String = "a"
    s match {
        case `target` => println("It was " + target)
        case _ => println("It was something else")
    }
}

does not compile:

error: stable identifier required, but target found. case target => println("It was " + target)

Why does Scala require a val not a var. I guess "Because" would be an acceptable answer but I have the feeling there is a deeper reas开发者_如何学Con I am missing.


I suspect that it's to enable table-switching optimizations for those cases where it is possible (without piles of checking to see whether it's valid). For example, with the code

class Sw {
  def m(i: Int) = {
    val a = 3
    val b = 2
    val c = 1
    i match {
      case `a` => 0
      case `b` => -1
      case `c` => 4
      case _ => 2
    }
  }
}

you get the bytecode

public int m(int);
  Code:
   0:   iconst_3
   1:   istore_2
   2:   iconst_2
   3:   istore_3
   4:   iconst_1
   5:   istore  4
   7:   iload_1
   8:   istore  5
   10:  iload   5
   12:  tableswitch{ //1 to 3
        1: 48;
        2: 44;
        3: 52;
        default: 40 }
   40:  iconst_2
   41:  goto    53
   44:  iconst_m1
   45:  goto    53
   48:  iconst_4
   49:  goto    53
   52:  iconst_0
   53:  ireturn

which would be much more complicated to do if you used vars (you'd have to detect whether they had changed to know whether that table expression was still valid).


There's nothing to stop you just turning your var into a val before using it in the match:

def mMatch(s: String) = {
    var target: String = "a"
    val x = target
    s match {
        case `x` => println("It was " + target)
        case _ => println("It was something else")
    }
}

works perfectly fine.


My guess is stable identifiers are required as a simplification to avoid situations where the variable changes inside the pattern matching itself. This would require clarification in the spec, and disrupt optimizations as Rex Kerr mentions.

var x: String = "a"
"b" match {
  case `x` if { x = "b"; true } => println("success")
}

Edit. But this explanation is not completely satisfactory, because the stable identifier could refer to a mutable object,

val x = collection.mutable.Seq(2)
def f(y: Seq[Int]) {
    y match {
      case `x` if { x(0) = 3; true } => println("success")
    }
}
f(Seq(2)) // success
f(Seq(2)) // failure

Note that a stable identifier is not necessarily known statically. For example, the following is fine,

def f(x: Int) {
  1 match { case `x` => println("hi") }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜