読者です 読者をやめる 読者になる 読者になる

null でメソッドを起動する

Scala では演算子もメソッドとして実装されていて、obj1 op obj2 なんてコードは、obj1.op(obj2) と同じ意味を持つ。
となると、気になってくるのは obj1 が null の場合どうなるのよ?ってことで・・・色々と試してみた。

scala> null == null
res0: Boolean = true

scala> null.==(null)
res1: Boolean = true

null でもメソッドは呼べるらしい。
ちょっとひねって、

scala> val nullStr: String = null
res2: String = null

scala> nullStr == "null"
res3: Boolean = false

scala> nullStr + "" == "null"
res4: Boolean = true

scala> nullStr.+(" str")
res5: String = null str

これも大丈夫。
てことは、メソッドの起動段階では null チェックが入らず、this に null が格納されうるということ?
って予想を立てて、こんな例。

scala> class Hoge {
     |   def isNull: Boolean = this == null
     | }
defined class Hoge

scala> new Hoge() isNull
res0: Boolean = false

scala> val n: Hoge = null
n: Hoge = null

scala> n isNull
java.lang.NullPointerException
        at .<init>(<console>:7)
        at .<clinit>(<console>)
        at RequestResult$.<init>(<console>:3)
        at RequestResult$.<clinit>(<console>)
        at RequestResult$result(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.i...
scala>

あれー?
てことは暗黙の型変換使うしかない・・・?

scala> class Hoge
defined class Hoge

scala> class ExHoge(val hoge: Hoge) {
     |   def isNull: Boolean = hoge == null
     | }
defined class ExHoge

scala> implicit def hogeWrapper(target: Hoge): ExHoge = new ExHoge(target)
hogeWrapper: (Hoge)ExHoge

scala> val n: Hoge = null
n: Hoge = null

scala> n isNull
res0: Boolean = true

scala> new Hoge isNull
res1: Boolean = false

scala>

おー、できた。
isNull の代わりに記号を使ってみる。

scala> class Hoge
defined class Hoge

scala> class ExHoge(val hoge: Hoge) {
     |   def ? : Boolean = hoge == null // 条件演算子じゃないよ!
     |                                  // ?(): Booleanを略して
     |                                  // ? : Booleanってしてるだけ!
     | }
defined class ExHoge

scala> implicit def hogeWrapper(target: Hoge): ExHoge = new ExHoge(target)
hogeWrapper: (Hoge)ExHoge

scala> val n: Hoge = null
n: Hoge = null

scala> n?
res0: Boolean = true

scala> new Hoge?
res1: Boolean = false

scala>

楽しい!
でも、もっと簡単に null 安全なメソッドが作りたい・・・
Scala では var よりも val の方が推奨されているらしいので、Java に比べれば null 安全なメソッドを作りたいという要求はあまり起こらないのかも。
Java でも Scala の暗黙の型変換を明示的に記述するような ExString とか作ってたし、それがより簡単に記述できるようになった、ってのは喜ぶべきかな。