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 引数が等しい場合に限り、マッチングは成功します。