れおの備忘録(´・ω・`)

〜なんでも書いちゃおう〜

ScalaでのSuspicious Shadowingについて

ある日。同僚から突然こんな問題が出題されました。

 def doSomething(x: Int, y: Int): Unit = y match {
    case `x` => println("A")
    case 0   => println("B")
    case 1   => println("C")
  }

  doSomething(1, 0) // => ?
  doSomething(0, 1) // => ?
  doSomething(1, 1) // => ?
  doSomething(0, 0) // => ?

【クイズ】 最後の4行はそれぞれA.B.Cのどれが出力されるでしょーか!

xのマッチが怪しいなぁ、とおもいつつも、B, C, C, Bしか思いつきませんでしたが、答えはなんと…

B, C, A, Aになります。

なんでかというと、x は、y == x のときに必ずマッチするからです。この機能は、Suspicious Shadowing と呼ばれるものらしいです。

言語仕様では、安定識別子 と記述されていました。

8.1.5 安定識別子パターン (Stable Identifier Patterns) 構文: SimplePattern ::= StableId 安定識別子パターンは安定識別子 r (§3.1)です。 r の型はパターンの要請型に適合しなくてはな りません。 パターンは、r == v である任意の値にマッチします(§12.1)。 変数パターンとの構文的な重なりを解決するため、安定識別子パターンは小文字で始まる単純名 ではいけません。 しかし、これはそのような変数名をバッククォートで囲めば可能で、そうす れば安定識別子パターンとして扱われます。 Example 8.1.2 次の関数定義を考えます。: def f(x: Int, y: Int) = x match { case y => ... } ここで y は、任意の値にマッチする変数パターンです。 もしこのパターンを安定識別子パター ンに変えたければ、次のようにます。: def f(x: Int, y: Int) = x match { case y => ... } これで、パターンは取り囲む関数 f の y パラメータにマッチします。 すなわち、f の x 引数 と y 引数が等しい場合に限り、マッチングは成功します。

Reference