Kotlin
A concise multiplatform language developed by JetBrains
Kotlin 1.4.20 リリース
Kotlin 1.4.20 では、新しい実験的な機能をお試しいただけます。 Kotlin チームはコミュニティからのフィードバックを取り入れることを基本方針としており、新機能のプロトタイプに関する皆さんの意見を募集しています。 ぜひお試しいただき、Slack(こちらで招待を取得できます)か YouTrack でフィードバックをお寄せください。
主なハイライトをいくつかご紹介します。
- invokedynamic 経由の文字列連結などの新しい JVM の機能をサポートしました。
- KMM プロジェクトのパフォーマンスと例外処理を改善しました。
- JDK Path:
Path(“dir”) / “file.txt”
の拡張関数。
また、既存の機能(1.4.0 で追加されたものを含む)に多数の修正と改善を加えました。 これらの機能のいずれかで問題が発生していた場合は、この機会にもう一度お試しください。
Kotlin 1.4.20 の機能に関する詳細を知りたい場合は、この記事を読み進めてください。 また、Kotlin ドキュメントの Kotlin 1.4.20 の新機能 ページでもリリースの簡単な概要を提供しています。 変更点の完全なリストは、変更ログで確認できます。
毎度のことながら、このリリースにご協力いただいた外部貢献者の皆さんに感謝いたします。
それでは詳しく見ていきましょう!
Kotlin/JVM
JVM では JVM 15 ターゲットを新たに追加しました。また、主に既存機能やパフォーマンスの改善とバグ修正に注力しました。
invokedynamic 文字列連結
Java 9 以降、JVM での文字列連結は動的なメソッド呼び出し(invokedynamic
バイトコード命令)を経由して実行されるようになりました。 これは以前の実装よりも高速に動作し、メモリ消費量が少なくなります。また、バイトコードを変更することなく将来の最適化のための余地を残します。
私たちはパフォーマンスを改善するためにこの仕組みを Kotlin に実装し始め、結果的に JVM 9 以降のターゲットで文字列連結を動的な呼び出しにコンパイルできるようになりました。
現時点では実験的な機能であり、次のケースに対応しています。
- 演算(
a + b
)、明示(a.plus(b)
)、参照((a::plus)(b)
)形式のString.plus
。 - インラインクラスとデータクラスの
toString
。 - 定数でない単一の引数を持つものを除く文字列テンプレート(KT-42457 を参照)。
invokedynamic
文字列連結を有効にするには、-Xstring-concat
コンパイラーオプションを追加して次のいずれかの値を指定してください。
indy-with-constants
を指定すると、StringConcatFactory.makeConcatWithConstants() を使用して文字列に対するinvokedynamic
連結を実行します(1.5 では JVM 9 以降のターゲットのデフォルト値になる予定です)。indy
を指定すると、StringConcatFactory.makeConcat() を使用して文字列に対するinvokedynamic
連結を実行します。inline
を指定すると、StringBuilder.append()
を使用する従来の連結に切り戻します。
Kotlin/JS
Kotlin/JS は急速に進化し続けており、このリリースではプロジェクトウィザード用の新しいテンプレート、プロジェクト構成をより適切に管理するための DSL の改善などを含むさまざまな改善が行われています。 新しい IR コンパイラーでは、エラーを無視してプロジェクトコンパイルするための新しい方法を提供します。
Gradle DSLの変更点
Kotlin/JS Gradle DSL には、webpack 構成の調整、自動生成される package.json ファイルの修正、推移的な依存関係に対する管理機能の向上など、プロジェクトのセットアップとカスタマイズを単純化する多数の更新が施されています。
一箇所で webpack を構成
Kotlin 1.4.20 では commonWebpackConfig
と呼ばれるブラウザー
ターゲット用の新しい構成ブロックが導入されています。 このブロックの中では、webpackTask
/ runTask
/ testTask
用の構成を複製せず、一箇所から共通の設定を調整できます。
これら 3 つのタスクに対してデフォルトで CSS を有効化するには、プロジェクトの build.gradle(.kts)
に次のスニペットを含めるだけです。
Gradle からの package.json のカスタマイズ
package.json
ファイルは一般的に JavaScript プロジェクトの動作を定義し、実行可能なスクリプトや依存関係などを特定するものです。 このファイルはビルド時に Kotlin/JS プロジェクト用に自動生成されます。 package.json
の中身は千差万別であるため、このファイルを簡単にカスタマイズする方法を求める多くのご要望をいただいていました。
Kotlin 1.4.20 からは、Gradle ビルドスクリプトから package.json
プロジェクトファイルにエントリを追加できます。 package.json
にカスタムフィールドを追加するには、compilations packageJson
ブロックの中で次のように customField
関数を使用します。
これにより、プロジェクトをビルドする際に次のブロックが構成ファイル build/js/packages/projectName/package.json
に追加されます。
"hello": { "one": 1, "two": 2 }
スクリプトフィールドを構成に追加してコマンドラインからプロジェクトを実行しやすくしたい場合でも、他の後処理ツール用の情報を含めたい場合でも、この新しいカスタムフィールドの指定方法が役に立つことを願っています。
選択的な yarn 依存関係の解決(実験的機能)
npm の依存関係を含める場合、その依存関係(推移的な依存関係)を詳細に管理したい場合があります。 このような要求にはさまざまな理由があります。 例えば、使用中のライブラリのいずれかの依存関係に重要なアップグレードを適用したいと思うかもしれません。 あるいは、アプリケーションの動作を妨げている推移的な依存関係のアップデートをロールバックしたいと思うこともあるでしょう。 Yarn の選択的な依存関係の解決により、元の作成者が指定した依存関係をオーバーライドして開発を続けることができます。
Kotlin 1.4.20 では、プロジェクトの Gradle ビルドスクリプトからこの機能を構成するための暫定的な(実験的な)方法を提供しています。 現在、私たちは API と他の Kotlin/JS オプションのスムーズな連携機能に取り組んでいますが、その間も YarnPlugin
内の YarnRootExtension
経由でこの機能を使用できます。 プロジェクト用に解決されるパッケージのバージョンに影響を与えるには、resolution
関数を使用してください。 この関数の引数で、パッケージ名セレクター(Yarn で指定されたとおりに)と必要なバージョンを指定します。
build.gradle.kts
ファイル内の選択的な依存関係の構成例は、このようになります。
ここでは、react
を要求するすべての npm 依存関係がバージョン 16.0.0
となり、processor
の decamelize
依存関係はバージョン 3.0.0
となります。 また、受け入れ可能なバージョンに関する制約を指定するための include
および exclude
の呼び出しを resolution
ブロックに渡すこともできます。
小さなワークスペースの無効化(実験的機能)
ビルド時間を短縮するため、Kotlin/JS Gradle プラグインは個別の Gradle タスクに必要な依存関係のみをインストールします。 例えば、webpack-dev-server
パッケージはいずれかの *Run
タスクを実行する場合のみインストールされ、 assemble
タスクを実行する場合にはインストールされません。 この仕組みによって不要なダウンロードが回避されますが、複数の Gradle プロセスを並列実行する場合には問題が発生する可能性があります。 依存関係の要件が競合した場合、2 つの npm パッケージのインストールが問題を引き起こす可能性があります。
この問題を解消するため、Kotlin 1.4.20 にはいわゆるgranular workspaces(小さなワークスペース)を無効化する新しい(実験的な)オプションが追加されています。 選択的な依存関係の解決を実験的にサポートしているのと同じように、この機能も現時点で YarnRootExtension
経由で使用できますが、他の Kotlin/JS Gradle DSL よりも密接に組み込まれる可能性があります。 この機能を使用するには、次のスニペットを build.gradle.kts
ファイルに追加してください。
この構成では、Kotlin/JS Gradle プラグインはプロジェクトで使用される可能性のあるすべての npm 依存関係(現在実行中ではないタスクで使用されるものも含む)をインストールします。 そのため、最初の Gradle ビルドには少々時間がかかる可能性がありますが、ダウンロードされる依存関係は実行するすべてのタスクに対して最新になります。 こうすることで、複数の Gradle プロセスが並行稼働する際の競合を回避できます。
新しいウィザードのテンプレート
作成中のプロジェクトをよりカスタマイズしやすくするため、Kotlin のプロジェクトウィザードに Kotlin/JS アプリケーション用の調整可能なテンプレートを新たに追加しました。 ブラウザーと Node.js 実行環境の両方に対応したテンプレートを用意しています。 これらのテンプレートはプロジェクトを開始し、初期構成を微調整するのに役立ちます。 また、新しい IR コンパイラーの有効化や追加ライブラリサポートのセットアップなどの設定が含まれています。
Kotlin 1.4.20 では、次の 3 種類のテンプレートを使用できます。
- Browser Application を使用すると、ブラウザーで動作する最小構成の Kotlin/JS Gradle プロジェクトをセットアップできます。
- React Application には適切な kotlin-wrappers を使用して React アプリのビルドを開始するのに必要なものがすべて含まれています。 また、スタイルシート、ナビゲーションコンポーネント、state コンテナーの組み込みを可能にするオプションを提供しています。
- Node.js Application はプロジェクトを Node.js ランタイムで実行できるように事前構成します。 また、以前の記事で紹介した実験的な kotlinx-nodejs パッケージを直接インクルードするオプションもあります。
コンパイルエラーの無視(実験的機能)
Kotlin 1.4.20 では、Kotlin/JS IR コンパイラーで コンパイルエラーを無視 できる新機能も使用できます。 この機能を使用すると、通常はコンパイルされない状態でもアプリケーションを試すことができます。 例えば、複雑なリファクタリングを行っている最中や、コンパイルエラーとは完全に無関係なシステムの一部で作業している場合が挙げられます。 この新しいコンパイラーのモードでは、コンパイラーはすべての異常コードを無視し、コンパイルを拒否する代わりに実行例外に置換します。
Kotlin 1.4.20 にはコード内のコンパイルエラーを無視するため、2 種類の許容ポリシーが導入されています。
SEMANTIC
モードでは、コンパイラーは構文的に正しいもののセマンティックに意味のないコードを受け付けます。 例えば、型の不一致があるステートメント(val x: String = 3
など)が挙げられます。SYNTAX
モードでは、コンパイラーはすべてのコードを受け付けます(構文エラーがあるものも含む)。 コードの記述内容を問わず、コンパイラーは実行可能ファイルの生成を試みます。
コンパイルエラーの無視は実験的な機能であるため、コンパイラーのオプションで明示的に指定する必要があります。 また、Kotlin/JS IR コンパイラーのみで使用できます。 この機能を有効化するには、次のスニペットを build.gradle.kts
ファイルに追加してください。
このようなエラーのあるコンパイルが、Kotlin/JS プロジェクトで作業する際にフィードバックのサイクルを強化し、イテレーションを高速化するのに役立つことを願っています。 皆さんからのフィードバックや、この機能を試した際に発見した問題を YouTrack でご報告いただけることを楽しみにしています。
私たちはこの機能の実装を継続的に改善しながら、この機能をどこかの時点で Kotlin/JS Gradle DSL とそのタスクとより高度に連携させる予定です。
Kotlin/Native
パフォーマンスは、1.4.20 でも引き続き Kotlin/Native の主な優先事項です。 この分野で鍵となる機能は、今後のリリースで強化と改善を予定している新しいエスケープ解析メカニズムのプロトタイプです。 また、範囲チェックの高速化(in
)などのより小規模なパフォーマンス改善も行われています。
また、1.4.20 では機能強化とバグ修正によって Kotlin/Native 開発の改善を行っています。 コード共有メカニズムなどの 1.4 の新機能で見つかった問題のほか、多数の古い問題にも対処しました。 これらの改善により、プロパティの初期化や関数参照での equals
と hashCode
の動作方法など、特殊な状況での Kotlin/Native と Kotlin/JVM との動作の不一致が修正されています。
さらに、Objective-C 相互運用機能を Objective-C の例外を Kotlin の例外にラップするオプションで拡張し、それらを Kotlin コード内で処理できるようにしました。
エスケープ解析
エスケープ解析は、あるオブジェクトはスタック上に割り当て可能かどうか、あるいはヒープに「エスケープ」すべきかどうかを判断するためにコンパイラーが使用する手法です。 スタック上での割り当てはかなり高速に実行され、将来的にガベージコレクションが必要になることはありません。
Kotlin/Native にはすでにローカルエスケープ解析が実装されていますが、今回は新しくより効率的なグローバルエスケープ解析のプロトタイプ実装を行っています。 この解析は、リリースビルドの個別のコンパイルフェーズで実行されます(-opt
コンパイラーオプションを使用します)。
このプロトタイプでは社内ベンチマークで平均 10 %のパフォーマンス向上を達成するなど、すでに有望な結果を得ています。 私たちはより多くのオブジェクトをスタックに割り当て、プログラムのさらなる高速化を図るためにアルゴリズムの最適化方法を調査しています。
私たちはこのプロトタイプに継続的に取り組んでいる間にこの機能を試し、実際のプロジェクトで得られた結果を共有していただけると非常に助かります。
エスケープ解析フェーズを無効化したい場合は、-Xdisable-phases=EscapeAnalysis
コンパイラーオプションを使用してください。
選択可能な Objective-C 例外のラッピング
Objective-C での例外の目的は、Kotlin のそれとは大きく異なっています。 例外の使用は通常、開発中にエラーを検出する目的に限定されています。 しかし、技術的には Objective-C ライブラリは実行中に例外をスローできます。 従来の Kotlin/Native にはこのような例外を処理するオプションがなく、ライブラリから NSException
がスローされると Kotlin/Native プログラム全体が終了していました。
1.4.20 では、実行中にこのような例外を処理し、プログラムのクラッシュを回避するためのオプションを追加しました。 NSException
を Kotlin の ForeignException
にラップし、Kotlin コードの処理を継続することを選択できるようになりました。 このような ForeignExeption
は元の NSException
への参照を保持しているため、根本的な原因に関する情報を取得するのに役立ちます。
Objective-C 例外のラッピングを有効化するには、cinterop
呼び出しで -Xforeign-exception-mode objc-wrap
オプションを指定するか、foreignExceptionMode = objc-wrap
プロパティを .def
ファイルに追加します。 CocoaPods 統合 を使用する場合は、次のように依存関係の pod {}
ビルドスクリプトブロックでオプションを指定してください。
デフォルトの動作は変わらず、プログラムは Objective-C コードから例外がスローされたときに終了します。
CocoaPods プラグインの改善
タスク実行の改善
このリリースでは、タスク実行の流れを大幅に改善しています。 例えば、新しい CocoaPods 依存関係を追加した場合、既存の依存関係は再ビルドされません。 また、既存のターゲットを追加した場合も、既存ターゲットの依存関係の再ビルドには影響しません。
DSL の拡張
1.4.20 では、CocoaPods 依存関係を Kotlin プロジェクトに追加するために DSL を拡張しました。
ローカルの Pod と CocoaPods リポジトリの Pod に加えて、次の種類のライブラリへの依存関係を追加できます。
- カスタム spec リポジトリのライブラリ。
- Git リポジトリのリモートリポジトリ。
- アーカイブのライブラリ(任意の HTTP アドレスでも入手できます)。
- 静的なライブラリ。
- カスタム cinterop オプションのあるライブラリ。
従来の DSL 構文も引き続きサポートされています。
次の例で DSL の変更点をいくつか確認してみましょう。
- Git リポジトリのリモートライブラリへの依存関係。 次の例のように、対応するキーワードを使用してタグ、コミット、ブランチを指定できます。
これらのキーワードを組み合わせて必要なバージョンの Pod を取得することもできます。
- カスタム spec リポジトリのライブラリへの依存関係。 この場合は特殊な
specRepos
パラメーターを使用します。
その他の例は、Kotlin と CocoaPods のサンプルにあります。
Xcode 統合の更新
Xcode を正常に処理するには、Kotlin でいくつかの Podfile を変更する必要があります。
-
Kotlin Pod に Git / HTTP / specRepo pod 依存関係がある場合は、それらを Podfile でも指定する必要があります。 例えば、CocoaPods リポジトリの
AFNetworking
への依存関係を追加する場合は、それを次のように Podfile でも宣言する必要があります。pod 'AFNetworking'
-
カスタム spec のライブラリを追加する場合は、Podfile の先頭でも spec の場所を指定する必要があります。
source 'https://github.com/Kotlin/kotlin-cocoapods-spec.git' target 'kotlin-cocoapods-xcproj' do // ... other Pods ... pod 'example' end
IntelliJ IDEA では統合エラーの詳細な説明が表示されるため、Podfile で問題が発生した場合は、その修正方法に関する情報をすぐに得ることができます。
Kotlin と CocoaPods のサンプルの withXcproject
ブランチを参照してください。 このブランチには、kotlin-cocoapods-xcproj
という既存の Xcode プロジェクトとの Xcode 統合の例が含まれています。
Xcode 12 ライブラリのサポート
Xcode 12 で提供される新しいライブラリを新たにサポートしました。 Kotlin のコードでこのライブラリを自由に使用してください!
マルチプラットフォームライブラリ公開の構造を刷新
Kotlin 1.4.20 以前では、マルチプラットフォームライブラリ公開にプラットフォーム固有の公開とメタデータ公開が含まれていました。 ただし、メタデータ公開だけに依存する必要はなかったため、このアーティファクトが明示的に使用されることはありませんでした。
Kotlin 1.4.20 以降は、個別のメタデータ公開は存在しません。 ライブラリ全体を表し、共通のソースセットに依存関係として追加された際に適切なプラットフォーム固有のアーティファクトに自動的に解決される、メタデータアーティファクトがルート公開に含まれるようになりました。
分類子を持たない空のアーティファクトを Maven Central のようなリポジトリの要件を満たす目的でライブラリのルートモジュールに追加することはできません。そのモジュールで現在インクルードされているメタデータアーティファクトと競合するためです。
1.4.20 で公開されるライブラリとの互換性
階層プロジェクト構造のサポートを有効化し、Kotlin 1.4.20 以上でそのようなサポートを有効にして公開されたマルチプラットフォームライブラリを使用する場合、プロジェクトの Kotlin も 1.4.20 以上にアップグレードする必要があります。
あなたがライブラリの作成者であり、階層プロジェクト構造のサポートを有効にしている Kotlin 1.4.20 以上でマルチプラットフォームライブラリを公開する場合は、階層プロジェクト構造のサポートも有効にしている旧バージョンの Kotlin のユーザーはそのライブラリを使用できなくなることに注意してください。 このようなユーザーは、Kotlin を 1.4.20 以上にアップグレードする必要があります。
ただし、あなたやあなたのライブラリのユーザーが階層プロジェクト構造のサポートを有効にしていない場合は、旧バージョンの Kotlin ユーザーは引き続きそのライブラリを使用できます。
詳細は、マルチプラットフォームライブラリの公開を参照してください。
標準ライブラリの変更
java.nio.file.Path 向けの拡張関数
1.4.20 以降の標準ライブラリでは、java.nio.file.Path
向けの実験的な拡張関数を提供しています。
慣用的な Kotlin 方法での最新 JVM ファイル API の処理が、kotlin.io
パッケージの java.io.File
拡張関数の処理に近づきました。 Files
の静的メソッドの大部分は Path
型の拡張関数として使用できるようになったため、それらを呼び出す必要はなくなりました。
この拡張関数は kotlin.io.path
パッケージ内にあります。 Path
自体は JDK 7 以上で使用できるため、拡張関数は kotlin-stdlib-jdk7
モジュール内に配置されています。 これらを使用するには、実験的なアノテーションである ExperimentalPathApi
を選択する必要があります。
これらの拡張関数を含む最初のプルリクエストを送信した貢献者である AJ Alt 氏には特に感謝しています。
String.replace
関数のパフォーマンス改善
私たちは常に Kotlin コミュニティからの機能改善の提案を楽しみにしていますが、次の内容もそのような提案の一つになります。 このリリースでは、String.replace()
関数の実装を変更しました。
大文字小文字を区別するバリアントは indexOf
ベースの手動置換ループを使用しますが、大文字小文字を区別しないバリアントは正規表現によるマッチングを使用します。
これにより、特定のケースにおける関数の実行速度が向上しました。
Kotlin Android Extensions の使用廃止
Kotlin Android Extensions は私たちが作成して以来、Android エコシステムにおける Kotlin の認知度向上に大きな役割を果たしてきました。 私たちはこれらの拡張関数と共に、ボイラープレートコードを削減するための便利で効果的なツールを開発者に提供していました。
- UI インタラクション用の合成ビュー(
kotlinx.android.synthetics
)。 - オブジェクトを
Parcel
のオブジェクトとして渡すためのParcelable
実装ジェネレーター(@Parcelize
)。
当初はさらなるコンポーネントを kotlin-android-extensions
に追加する予定でした。 しかし、この予定は取りやめになり、プラグインを個別の部分に分割してほしいというユーザーからの要望もありました。
その一方、常に Android エコシステムは進化しており、開発者は作業の負荷を減らす新しいツールを入手しています。 Kotlin Android Extensions がこれまで埋めていたギャップは、Google が提供する仕組みによってカバーされています。 例えば、UI インタラクション用の簡潔な構文については、Kotlin の synthetics と同様に findViewById
を置き換えるビューバインディングを備えた Android Jetpack が存在します。
これらの 2 つの要素を考慮し、ビューバインディングを優先して synthetics を廃止し、Parcelable 実装ジェネレーターを個別のプラグインに移動することにしました。
1.4.20 では kotlin-android-extensions
から Parcelable 実装ジェネレーターを抽出し、それ以外の部分に対する使用廃止サイクルを開始しました。現在残っているのは synthetics のみです。 現状は非推奨の警告付きで機能し続けます。 将来的にはプロジェクトを別のソリューションに切り替える必要が生じます。 詳細は、Android プロジェクトを synthetics からビューバインディングに移行するためのガイドラインを参照してください。
Parcelable 実装ジェネレーターを新しい kotlin-parcelize
プラグインで使用できるようになりました。 synthetics を使用し続ける場合は、kotlin-android-extensions
の代わりに、またはそれに加えてこのプラグインを 利用してください。 @Parcelize
アノテーションは kotlinx.parcelize
パッケージに移動されています。
アップデート方法
プロジェクトを Kotlin の最新バージョンに合わせて更新する前に、新しい言語と標準ライブラリの機能をオンライン(play.kotl.in)で試すことができます。
IntelliJ IDEA と Android Studio では Kotlin プラグインをバージョン 1.4.20 にアップデートできます。手順については、こちらを参照してください。
Kotlin の旧バージョンで作成された既存のプロジェクトで作業する場合は、プロジェクトの構成で 1.4.20
を Kotlin のバージョンに使用してください。 詳細については、Gradle と Maven のドキュメントを参照してください。
コマンドラインコンパイラーは、GitHub リリースページからダウンロードできます。
このリリースでは、以下のバージョンのライブラリを使用できます。
- kotlinx.atomicfu バージョン 0.14.4
- kotlinx.coroutines バージョン 1.4.1
- kotlinx.serialization バージョン 1.0.1
- ktor バージョン 1.4.1
- kotlinx.html バージョン 0.7.2
- kotlinx-nodejs バージョン 0.0.6
kotlin-wrappers
からのライブラリのバージョン(kotlin-react
など)は、対応するリポジトリで確認できます。
リリースの詳細と互換性のあるライブラリの一覧は、ここから入手できます。
この新リリースで問題が発生した場合は、Slack (こちらで招待を取得できます)で支援を求めるか、YouTrack で課題を報告してください。
外部貢献者
このリリースに含められた Pull リクエストは、次の外部貢献者からいただきました。ご協力いただきありがとうございました。
Jinseong Jeon
Toshiaki Kameyama
Steven Schäfer
Mads Ager
Mark Punzalan
Ivan Gavrilovic
pyos
Jim Sproch
Kristoffer Andersen
Aleksandrina Streltsova
cketti
Konstantin Virolainen
AJ Alt
Henrik Tunedal
Juan Chen
KotlinIsland
Valeriy Vyrva
Alex Chmyr
Alexey Kudravtsev
Andrey Matveev
Aurimas Liutikas
Dat Trieu
Dereck Bridie
Efeturi Money
Elijah Verdoorn
Enteerman
fee1-dead
Francesco Vasco
Gia Thuan Lam
Guillaume Darmont
Jake Wharton
Julian Kotrba
Kevin Bierhoff
Matthew Gharrity
Matts966
Raluca Sauciuc
Ryan Nett
Sebastian Kaspari
Vladimir Krivosheev
n-p-s
Pavlos-Petros Tournaris
Robert Bares
Yoshinori Isogai
Kris
Derek Bodin
Dominik Wuttke
Sam Wang
Uzi Landsmann
Yuya Urano
Norbert Nogacki
Alexandre Juca