Scalaの演算子はメソッド、ではなぜ==がぬるぽにならないのか
2015/03/22
Scalaの本やblogを読んでいるとScalaの演算子はメソッドである、という説明が出てきます。
今日はその話です。
+演算子をメソッド呼び出しで
実際にやってみると・・・
scala> val a = 10 a: Int = 10 scala> val b = 20 b: Int = 20 scala> val res1 = a + b res1: Int = 30 scala> val res2 = a.+(b) res2: Int = 30
a.+(b)が成功します。
==演算子をメソッド呼び出しで・・・ぬるぽにならない
ここで一つ疑問が生まれます。
「==もメソッド呼び出しであるのならば、==のCaller側がnullだったらぬるぽになるんじゃないの?」です。
scala> val a = null a: Null = null scala> val b = 20 b: Int = 20 scala> val res = a.==(b) <console>:9: warning: comparing values of types Null and Int using `==' will always yield false val res = a.==(b) ^ res: Boolean = false
(warningは出ていますが、それは一旦置いておいて)NullPointerExceptionが発生していません。Javaならaがnullならぬるぽになりますね。Scalaでもaがnullの状態で他のメソッドを呼び出すとぬるぽになります。
例えば
scala> val nullString: String = null nullString: String = null scala> nullString.length java.lang.NullPointerException ... 33 elided
なぜ==だけ・・・と思ってscalajp/public – Gitterで質問したら@xuwei_kさんが教えてくれました。
どうやらScalaコンパイラの仕様みたいです。nullチェックのコードを自動で仕込むから、だそうです。
逆コンパイルで確認
以下のコードをscalacでコンパイルして、JavaDecompilerで逆コンパイルし、確認してみます。
元コード
object Main extends App { val a = null val b = 20 if(a == b) println("equal!!!") else println("not equal...") }
実行結果
[tsukaby@tsukamac tmp]% scala Main not equal...
逆コンパイル結果の一部
public final void delayedEndpoint$Main$1() { this.a = null; this.b = 20; a(); localInteger = BoxesRunTime.boxToInteger(b()); tmp25_16 = null; if (tmp25_16 == null) { tmp25_16; if (localInteger == null) break label44; tmpTernaryOp = tmp25_16; break label55; } }
分かりづらいですが、勝手にifによるnullチェックが入っています。
という訳で、ぬるぽにならないことが分かりました。