Kotlin 1.0 Beta 4の変更点


Kotlin Advent Calendar 2015の23日目の記事です。

22日目は@rabitarochanさんによるKotlinのプロパティをタイプセーフに取得するでした。

今日の内容なのですが、ちょうど昨日にKotlin 1.0 Beta4が出たので変更点を翻訳してみました。

インクリメンタルコンパイルの改善 (Experimental)

Kotlinのインクリメンタルコンパイルをもっと素早く実行するために、新しく精確な依存検出アルゴリズムを作ったよ.
これはまだexperimentalだけど、僕らがすでにつかっているユースケースだととてもうまく動いてる.
使うためには次の設定をやってみてね.

Settings |
Build, Execution, Deployment |
Compiler |
Kotlin Compiler |
Enable precise incremental compilation (experimental)

同じインクリメンタルコンパイルサポートがGradleにも来るよ. 楽しみにしててね.

言語

すべての変更点からいくつかハイライトを説明するよ.

オーバーロードの解決アルゴリズムの変更

オーバーロードの解決アルゴリズムの修正によって、Kotlinでは現在SAM-converted Java関数をよりメンバー(関数?)のように取り扱うよ. (以前はextensionsのように振る舞うために使ってた).
この修正は重要なんだ. なぜならそうしないと多くの場合でコンパイラによって面倒な方法で(オーバーロードを)解釈しなくてはならなかった.

残念ながら, 結果として壊れてしまっている比較的一般的なケースが少なくとも1つある.
だけど, この修正自体は非常に簡単だ.
現在コンパイラは file.listFiles { it.name == "..." } に対して指摘をしてくれる.
この理由はちょっと複雑

  • java.io.FileのlistFilesには3つのオーバーロードがある
  • この内2つがSAM-interfaceを持っている. これらはlambdaを保持しうるため変換をかける
  • 故に, パラメータのないlambdaが通ってきた時にどれを選ぶべきなのか判断がつかない.
  • 以前は動いていた, なぜなら古いライブラリの拡張関数が (SAM以前の時代に戻ったとき) SAM-converted メンバーの代わりに選択されるからだ.

解決方法はシンプル. 単にパラメータを特定させてあげるだけでいい. 例えば次のような感じ

file.listFiles { it -> ... }

プロパティがパラメータのない関数オブジェクトとして利用できる

例: Kotlinにおいて String::length はプロパティであり、関数でない.
だが関数が期待される場所で使うことができたら便利だ. 例えば次のような感じ.

val lengths = strs.map(String::length)

なので、この書き方を認めることにした. 言い方をかえると, (R) -> T という関数として期待されるAPIがあるならば, 返り値の型をTとしたRのプロパティの参照を利用することができる.

将来利用するキーワードの予約

僕らはKotlinの将来のリリースに備えていくつか新しい機能を追加しようと計画している. だから予め必要なキーワードを予約することを決めたんだ.
未来のすべてを予想することをできないと理解してる. だけどここに挙げるものは頑張って予想してみたものだ (未来の機能はまだ詳細にはデザインできてないけれど, これらを使ってできうる限り便利にしていくつもり)

  • yield はキーワードとして予約
  • sealedwhen の事前語で予約
  • typeof はキーワードとして予約. JSでは, jsTypeOf() を使う
  • async{fun の事前語で予約.

よって, 現在では, async {...}の代わりに async () {...} で宣言しなくてはならない.
これが綺麗ではないことは承知しているのだけど, いいオプションを見つけることができなかった. コード補完では () が自動で挿入されるようになっている.

Code Cleanup で既存のコードからの移行は手助けしてくれる.

Java Wildcards

どのようにKotlinが変数型を変換するのかでいくつか問題があった. 例えば, List<Foo> が Javaの List<? extends Foo> であるべきなのか 単に List<Foo> であるべきなのかといった問題だ.
詳細はさておき, 次を決定した.

  • デフォルトでは, 返り値や意味のない場所ではワイルドカードを生成しない
  • ワイルドカードが必要とされるときには, 型アノテーション付きで強制することができる. List<@JvmWildcard String> は常に Javaの List<? extends String> となる
  • ワイルドカードを取り除く必要があるときには, @JvmSuppressWildcards を利用する (これは型の上、もしくはこれを含む宣言で利用できる)

例:

fun foo(l: List<String>) // in Java: List<String> (String is final)
fun foo(l: List<@JvmWildcard String>) // in Java: List<? extends String>

interface Open
fun bar(p: List<Open>) // in Java: List<? extends Open> (Open is not final)
@JvmSuppressWildcards
fun bar(p: List<Open>) // in Java: List<Open>

注意: これはコレクションのみでなく, declaration-site variance を含むすべての型で配慮される

ライブラリの変更

標準ライブラリを整理している. これはいくつかリパッキングも含んでいる.

  • kotlin.test パッケージは別個のjar-file kotlin-test.jar として移動した. quick fixはIDE上で利用可能で, 自動で依存を追加してくれる.
  • 標準ライブラリの中でパッケージの並べ替えの準備をしている. 新しいパッケージを作り, すべての関数をそれらにコピーした. 古い関数はバイナリ互換のために残されている. Kotlinのコード上で移行する必要はない, JavaのコードではCode Cleanup が利用可能だ

後々, ライブラリから1つ以上のJARを抽出することを予定している. これはあまり頻繁には使われないarray utilitiesを含んでいる. それでメインのJARから外出しすることでサイズを減らしたいんだ.

さらにハイライト

KotlinのInt::classは 違うコンテキストでは Javaの int.class もしくは Integer.class に対応するかもしれない. 2つの内で特定の一つが必要なケースを楽に使えるように、2つのプロパティを導入した.

  • Int::class.javaPrimitiveTypeInt.class を返却する
  • Int::class.javaObjectTypeInteger.class を返却する

また IntArray(5) { it * 3 } のようなものも宣言できる. すなわち 初期化されたプリミティブな配列が作成できる

将来の変更: collectionの中のnullの意味について

後々のバージョンのJDKはよりさらにnullを許容できないようなcollectionを作成している. 例えば, JavaDocいわく java.util.Map.computeIfAbsent

もし特定のkeyがまだvalueと紐付いていない (もしくはnullにマッピングされている)ならば、
その値を与えられたmapping関数を利用して計算しようと試み、nullでないようにこのマップに入力しようとする  

これら規約は、こういった操作を行うアトミックなプロパティに対して本質的なので、僕らもそれにそぐうように決めた.
だけれども null-freeなconcurrent collectionを操作しようとした時にKotlinのextension関数では適切な振る舞いを保証することができない.
なので, getOrPutなど同じくnull値が現れないように扱う関数の振る舞いを変えようとしている.

あなたのコードをupdateするために, deprecation warningsの推奨に従ってほしい.

IDEの新しい機能

  • 解決されない参照のためのQuick-fixが追加された. コードを違うコンテキストにペーストするときなど, シンボルの名前を調整するのにお手軽だ.

  • 現在 IDEでは解決されない呼び出し可能な参照から関数を作ることができる.

  • Go to TestCreate Test アクションがトップレベルの関数として動作する

  • 無名関数からlambda記述へ変更するintentionが追加された

  • Go to classSearch everywhere が Kotlinの組み込み型を表示するようになった

  • デバッガ: 'Skip simple getter' オプションがサポートされた. これはデバッガがコンストラクターで宣言されたプロパティやgetterなしのプロパティ、またフィールド値を返すgetterで止まらないことを意味している.

今後

Beta期間が終わったあとには, RCと1.0が待っている.

僕らは1.0のあとにpre-releaseバージョンのKotlinでコンパイルされたコードがないかを確かめたいと思っている. だから RCのコンパイラですべての古いコードを強制的に再コンパイルするだろう. JetBrainsの外のライブラリメンテナーとも一緒に, その時広く利用されているすべてのライブラリが再コンパイルされるということを確認したい.

また僕らはここでレガシーさを取り除くための機会を得るつもりだ.

  • ライブラリが進化していく過程で積み重ねられたすべての依存は取り除く
  • 自動生成されたコードからのすべての依存は取り除く (聞いたことがないかもしれないけれど, 存在するんだよ!)
  • ベータ期間中に見つかったレガシーなバイトコードの特性を取り除く
  • さらに構造を持っているパッケージがあるので, stdlib周りのコードを移動する

その点については, 標準ライブラリは互換性のある変更、deprecationとaddtionのみだ (ただしreflection APIは除く). 重要な点を見落としてないか確認するために, 僕らは現在open review をライブラリAPIに対して走らせている.

メリー, Kotlin!


以上でした. RC楽しみですね.
翻訳は, いろいろ間違っている点あると思うので編集リクエストいただけると助かります.

明日はyy_yankさんです!