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

kmizuの日記

プログラミングや形式言語に関係のあることを書いたり書かなかったり。

Kotlinのnullable typeはzero overheadではありません

タイトルの通りなんですが、JetBrainsさんが公式で

Zero-overhead null-safety

とか書いているおかげで信じている人もいるかもしれません。ですが、それは正しくありません。

試しに、次のコードをコンパイルしてみましょう。

fun double(x: Int?): Int = x?.let{ it * it } ?: 0 

クラスファイル BoxingKt.class が生成されるので、javapしてみましょう。

Compiled from "Boxing.kt"
public final class BoxingKt {
  public static final int foo(java.lang.Integer);
    Code:
       0: aload_0
       1: dup
       2: ifnull        21
       5: astore_1
       6: nop
       7: aload_1
       8: checkcast     #9                  // class java/lang/Number
      11: invokevirtual #13                 // Method java/lang/Number.intValue:()I
      14: istore_2
      15: iload_2
      16: iload_2
      17: imul
      18: goto          23
      21: pop
      22: iconst_0
      23: ireturn
}

まず、引数の型がjava.lang.Integerになっています。これは、引数を渡す時にBoxingのコストが発生することを意味します。また、その値を使って計算する場合、Unboxingのコストが発生します。

この問題は、プリミティブな型をnullableにしたときに発生します。ジェネリクスでプリミティブ型相当を引数にしたときにBoxingが発生するのと理屈は同じです。

必ずしもこの点が問題にはならないとは思いますが、一般にKotlinのnullable typeがzero overheadというのはだと言って良いでしょう。