Why can't a variable be a stable identifier?

后端 未结 3 1679
滥情空心
滥情空心 2020-12-10 10:11

The following

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


        
相关标签:
3条回答
  • 2020-12-10 10:40

    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).

    0 讨论(0)
  • 2020-12-10 10:41

    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.

    0 讨论(0)
  • 2020-12-10 10:57

    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 讨论(0)
提交回复
热议问题