KotlinでAndroidアプリを開発しているときに,APKの中を見ると kotlin/kotlin.kotlin_builtins
のような *.kotlin_builtins
ファイルや META_INF
下に *.kotlin_module
という見覚えの無いファイルが含まれていて,リリース時に含めるべきファイルなんだろうか?と思って気づいたらKotlinのコード読んだりclassファイル読んだりしていました.
*.kotlin_builtins
と*.kotlin_module
については,結論から言えば kotlin-reflect
でリフレクションをしたりKotlinの型情報を実行時に扱う黒魔術に手を染めてない限りは実行時に使わないのでAPKに含めなくて良さそう.
Kotlin正式サポートされたので,将来的には不要な場合にはAPKに含めないようになるのかも.
以下,あまりAndroid関係ない内容です.
*.kotlin_builtins
Kotlinの組み込み型に関する型情報が入っている.
リフレクション時やコンパイル時の他に,IDEのプラグインとかも参照している.
ファイルの中身はProtocol Buffersでエンコードされている.
*.kotlin_module
Kotlinのモジュール単位で必要に応じて作られるファイル.
クラスの外に実装されたトップレベルの関数やtypealias
等に関する情報などが入っている.
色々
Metadataアノテーション
組み込み型の型情報は,kotlin_builtinsファイルで管理されているみたいだけど,通常のクラスはどうかと見てみるとKotlinのクラスには,謎のMetadataアノテーションが付いている.
- ScalaにもScalaSignatureというのがあったけどほぼ同じようなもの
- 中見ると謎データ入っているけど,これもProtoBufでエンコードされたメソッド等の型情報
kotlin-reflect
とか使うなら,ProGuardに削除されないように気をつける必要がありそう.
逆にリフレクションとかしないならProGuardに削除されるのでサイズのオーバーヘッド考えなくて良い.
interfaceのデフォルト実装
- デフォルト実装をstaticメンバとして持った
$DefaultImpls
クラスが生成される - インタフェイスを実装しているクラスでoverrideしていなければ,実装クラスのメソッドを呼び出すだけのメソッドが追加される
- インライン展開っぽいことはしないみたい
トップレベル関数
classの外に書かれたトップレベル関数はファイル名 + Kt
という名前のクラスが生成され,そこに定義される.
Kotlinのコンパイル単位をまたいで参照する場合,それがトップレベル関数であることがわからなくなりそうですが,どのクラスファイルがトップレベル関数を持っているかの情報が,META_INF 内の *.kotlin_module
に入ってるのでこれをれ見て解決される.
classファイルが自動生成されますが,$
とか入ってないので,うっかりKt
で終わるクラス作ると普通に衝突する.
拡張関数
扱いはトップレベル関数とほぼ同じ.static
メソッドになっててthis
が引数で受け取ったオブジェクトに置き換えられている.
nullチェック
KotlinではNullableが明確に区別されていますが,javaからKotlinの関数を呼ぶ時にNullableでない箇所にnullを入れると例外が飛びます.
内部的には各メソッドの先頭で internal.Intrinsics.checkNotNull でnull チェックされてます.
privateメソッド等,明らかにnullが渡って来ない場所ではチェックは省略されます.
コレクションクラスの mapやfold
Listとかに mapやfold生えててとても嬉しい.
コンパイル後のコード見たら,単純なコードならインライン展開されててただのループだし安心.躊躇なく使って良さげ.
最後に
巷で言われている通り,Javaと比べて生成されるコードサイズも実行速度もほとんどオーバーヘッドは無さそう.
Kotlin自体は3年以上前から触ってますが,話題になったときにたまに思い出して触るにわかなのでいい加減なこと書いてるかも.