1
0

More than 1 year has passed since last update.

Kotlin 1.6.20の変更点

Posted at

※ソース記事はこちら
※Kotlin/JSやKotlin/Nativeについては個人的に使っていないので、割愛します。
Kotlin 1.6.20により、将来の言語機能のプレビューが明らかになり、マルチプラットフォームのプロジェクトのために階層構造がデフォルトになり、他のコンポーネントに進化的な改善がもたらされている。
こちらの動画でも、変更の短い概要を見ることができる。

言語

Kotlin 1.6.20では、2つの言語の特徴を試すことができる。

  • Kotlin/JVMのためのコンテキストレシーバーのプロトタイプ
  • 明確なnon-nullable型

Kotlin/JVMのためのコンテキストレシーバーのプロトタイプ

この機能はKotlin/JVMのためにのみ利用可能なプロトタイプである。-Xcontext-receiversを有効にすることで、コンパイラは本番コードでは利用できないプレリリースのバイナリを生成するだろう。おもちゃのプロジェクトでのみコンテキストレシーバーを使うこと。You Trackでフィードバックをいただけると幸いである。

Kotlin 1.6.20では、もはや一つのレシーバーに限定されることはない。より必要なら、宣言にコンテキストレシーバーを追加することで、関数、プロパティ、クラスをコンテキスト依存(あるいはコンテキスト的)にすることができる。コンテキストの宣言は次のように行う。

  • すべてのコンテキストレシーバーは、暗黙のレシーバーとして、呼び出し側のスコープに存在する必要がある。
  • 宣言されたコンテキストレシーバーは、暗黙のレシーバーとして、本体のスコープにもたらされる。
interface LoggingContext {
    val log: Logger // このコンテキストはloggerへの参照を提供する
}

context(LoggingContext)
fun startBusinessOperation() {
    // LoggingContextは暗黙のレシーバーなので、logプロパティにアクセスすることができる
    log.info("Operation has started")
}

fun test(loggingContext: LoggingContext) {
    with(loggingContext) {
        // startBusinessOperation()を呼び出すためには、スコープ内でLoggingContextを
        // 暗黙のレシーバーにする必要がある
        startBusinessOperation()
    }
}

コンテキストレシーバーをプロジェクトで有効にするには、-Xcontext-receiversコンパイラオプションを使う必要がある。この機能と文法についての詳細な説明は、KEEPで見つけられる。
留意すべきは、実装はプロトタイプであるということである。

  • -Xcontext-receiversを有効にすると、コンパイラは本番コードでは利用できないプレリリースのバイナリを生成するだろう。
  • コンテキストレシーバーのためのIDEのサポートは、現状最小限である。

この機能を試し、こちらのYouTrack課題で、この機能に対する考えと体験について、共有してほしい。何か問題にぶつかったら、是非新しい課題を提出していただきたい。

明確なnon-nullable型

明確なnon-nullableな型はBetaである。これらはほぼ安定しているが、将来、移行手順が必要になるかもしれない。しなければならない変更を最小限にするため、ベストを尽くすつもりである。

ジェネリクスのJavaのクラスとインターフェイスを継承するときに、より良い相互運用性を提供するため、Kotlin 1.6.20では、新しい文法である、T & Anyとともに、ジェネリクスの型パラメータを利用場所で明確にnon-nullableと印をつけることが可能である。この文法の形は、交差型の記法から由来しており、現在、&の左側のnullableな上限境界を持つ型パラメータと、右側のnon-nullableなAnyに限定されている。

fun <T> elvisLike(x: T, y: T & Any): T & Any = x ?: y

fun main() {
    // OK
    elvisLike<String>("", "").length
    // Error: 'null' は、non-null型の値として許可されない
    elvisLike<String>("", null).length

    // OK
    elvisLike<String?>(null, "").length
    // Error: 'null' は、non-null型の値として許可されない
    elvisLike<String?>(null, null).length
}

この機能を有効にするには、言語バージョンを1.7に設定すること。

kotlin {
    sourceSets.all {
        languageSettings.apply {
            languageVersion = "1.7"
        }
    }
}

こちらのKEEPで、明確なnon-nullable型について、知識を深める。

Kotlin/JVM

Kotlin 1.6.20では次のものが導入されている。

インターフェイスのための新しい@￰JvmDefaultWithCompatibilityアノテーション

Kotlin 1.6.20では、新しいアノテーションである、@JvmDefaultWithCompatibilityが導入されており、-Xjvm-default=allコンパイラオプションとともに使い、すべてのKotlinインターフェイスのうちすべての抽象でないメンバーのために、JVMインターフェイスデフォルトメソッドを作る
もし-Xjvm-default=all無しでコンパイルされたKotlinインターフェイスを使うクライアントがある場合、このオプションでコンパイルされたコードとはバイナリ非互換になるかもしれない。Kotlin 1.6.20より前では、この互換性の問題を避けるため、推奨するアプローチは、-Xjvm-default=all-compatibilityモードでかつ、この種の互換性が不要なインターフェイスに@JvmDefaultWithoutCompatibilityアノテーションを使うことだった。
このアプローチはいくつか不利な点があった。

  • 新しいインターフェイスが追加されたときに、アノテーションを追加することを容易に忘れうる。
  • 大抵、公開APIよりも非公開な部分で多くのインターフェイスがあり、コードの中の多くの箇所でこのアノテーションを持つことになる。

今では、-Xjvm-default=allモードと、@JvmDefaultWithCompatibilityアノテーションで、インターフェイスをマークすることができる。これにより、公開API内の全インターフェイスに一度このアノテーションを追加し、新しい公開でないコードには一つもアノテーションを使う必要がなくなる。
このYou Trackチケットで、この新しいアノテーションについてのフィードバックを残してほしい。

-Xjvm-defaultモードでの互換性の変更

Kotlin 1.6.20では、-Xjvm-default=allまたは-Xjvm-default=all-compatibilityでコンパイルされたモジュールに対して、デフォルトモード(-Xjvm-default=disableコンパイラオプション)でモジュールをコンパイルするオプションが追加されている。従来通り、すべてのモジュールが-Xjvm-default=allまたは-Xjvm-default=all-compatibilityモードを持っている場合にも、コンパイルは成功するだろう。You Track課題にフィードバックを残していただくことができる。
Kotlin 1.6.20では、-Xjvm-defaultコンパイラオプションの、compatibilityenableが非推奨である。互換性に関する他のモードの説明に変更があるが、全体的なロジックは同じ状態のままである。更新された説明を、調べることができる。
Java相互運用性におけるデフォルトメソッドに関しての、より詳細については、相互運用性ドキュメントこちらのブログ投稿を参照のこと。

JVMバックエンドでの単一のモジュールの並列コンパイルのサポート

JVMバックエンドでの単一のモジュールの並列コンパイルのサポートは実験的である。いつでも中止か変更になるかもしれない。オプトインが必要(詳細は以下)であり、評価のためにのみ、使うべきである。You Trackでフィードバックをいただけると幸いである。

新しいJVM中間表現のバックエンドにおいて、コンパイル時間の改善が継続的に行われれている。Kotlin 1.6.20では、並列にモジュール内の全ファイルをコンパイルするための実験的なJVM中間表現モードが追加されている。並列コンパイルは、全体のコンパイル時間を最大15%減らすことができる。
-Xbackend-threadsコンパイラオプションで、実験的な並列バックエンドモードを有効にすること。このオプションには、次の引数を使う。

  • Nは、使うスレッド数である。これはCPUコア数よりも大きくすべきではない。そうしないとスレッド間のコンテキストスイッチのために、並列化の効果がなくなってしまう。
  • 0はそれぞれのCPUコアで別々のスレッドを分けて使う。

Gradleでは、タスクを並列に実行することができるが、この種の並列化は、プロジェクト(あるいはプロジェクトの大部分)がGradleの視点から、大きな一つのタスクであるときには、あまり役に立たない。もし非常に大きなモノシリックなモジュールがある場合は、より早くコンパイルするには、並列コンパイルを使うこと。もしプロジェクトが多くの小さなモジュールから構成されており、Gradleによって並列にビルドされている場合は、別の並列化レイアが追加されることで、コンテキストスイッチにより、性能が劣化するかもしれない。

並列コンパイルはいくつかの制約がある。

  • kaptは中間表現バックエンドを無効にするため、kaptとは連携しない。
  • 設計により、より多くのJVMヒープ領域を必要とする。ヒープの量はスレッド数に比例する。

関数インターフェイスのコンストラクタに対する関数参照のサポート

関数インターフェイスのコンストラクタに対する関数参照のサポートは実験的である。いつでも中止か変更になるかもしれない。オプトインが必要(詳細は以下)であり、評価のためにのみ、使うべきである。You Trackでフィードバックをいただけると幸いである。

関数インターフェイスのコンストラクタに対する関数参照のサポートにより、コンストラクタ関数を持つインターフェイスから、関数型のインターフェイスへ移行する、ソースレベルで互換性のある方法が追加される。
次のコードを考えてみよう。

interface Printer {
    fun print()
}

fun Printer(block: () -> Unit): Printer = object : Printer { override fun print() = block() }

関数インターフェイスのコンストラクタに対する関数参照により、このコードは単に関数インターフェイスの宣言に置き換えられる。

fun interface Printer {
    fun print()
}

コンストラクタは暗黙的に作られ、::Printer関数参照を使うすべてのコードはコンパイルされる。例えば次のように。

documentsStorage.addPrinter(::Printer)

レガシーなPrinter関数は、DeprecationLevel.HIDDENを持つ@Deprecatedアノテーションがマークして、バイナリ互換性を保持すること。

@Deprecated(message = "非推奨についてのメッセージを追加する", level = DeprecationLevel.HIDDEN)
fun Printer(...) {...}

この機能を有効にするには、-XXLanguage:+KotlinFunInterfaceConstructorReferenceコンパイラオプションを使うこと。

セキュリティ ※割愛

Gradle

Kotlin 1.6.20では、次の変更がKotlin Gradleプラグインにもたらされている。

Kotlinコンパイラ実行戦略を定義するプロパティ

Kotlin 1.6.20より前は、Kotlinコンパイラ実行戦略を定義するために、-Dkotlin.compiler.execution.strategyシステムプロパティが使われていた。このプロパティはいくつかのケースで使いづらいかもしれなかった。Kotlin 1.6.20では、同じ名前である、kotlin.compiler.execution.strategyGradleプロパティと、コンパイルタスクプロパティであるcompilerExecutionStrategyが導入されている。
システムプロパティはまだ動作するが、将来のリリースで削除されるだろう。
プロパティの現在の優先順位は次のとおりである。

  • タスクプロパティであるcompilerExecutionStrategyは、システムプロパティと、Gradleプロパティであるkotlin.compiler.execution.strategyよりも優先する。
  • Gradleプロパティはシステムプロパティよりも優先する。

これらのプロパティには3つのコンパイラ実行戦略を割り当てることができる。

戦略 Kotlinコンパイラが実行される場所 インクリメンタルコンパイル その他の特徴
Daemon 自身のデーモンプロセス内 可能 デフォルトの戦略。異なるGradleデーモン間で共有可能
In process Gradleデーモンプロセス内 不可 Gradleデーモンとヒープを共有可能
Out of process それぞの呼び出しごとに別プロセス内 不可 -

さらに、kotlin.compiler.execution.strategyプロパティ(システムとGradle両方)に対して利用可能な値は以下である。

  1. daemon(デフォルト)
  2. in-process
  3. out-of-process

gradle.properties内で、kotlin.compiler.execution.strategyGradleプロパティを次のように使うこと。

# gradle.properties
kotlin.compiler.execution.strategy=out-of-process

compilerExecutionStrategyタスクプロパティの利用可能な値は以下である。

  1. org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.DAEMON(デフォルト)
  2. org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.IN_PROCESS
  3. org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.OUT_OF_PROCESS

compilerExecutionStrategyタスクプロパティは、build.gradle.ktsビルドスクリプト内で、次のように使うこと。

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy

// …

tasks.withType<KotlinCompile>().configureEach {
    compilerExecutionStrategy.set(KotlinCompilerExecutionStrategy.IN_PROCESS)
}

こちらのYou Track課題にフィードバックを是非残してもらいたい。

kaptとコルーチンのためのビルドオプションの非推奨

Kotlin 1.6.20では、プロパティの非推奨レベルが変更された。

  • kapt.use.worker.apiで、Kotlinデーモン経由で、kaptを実行できることが非推奨になった。現在は、Gradleの出力に警告が生成される。デフォルトでは、1.3.70のリリースからkaptはGradleワーカーを使っており、この方法を踏襲することを推奨する。
    将来のリリースでは、kapt.use.worker.apiオプションは削除される予定である。
  • kotlin.experimental.coroutines Gradle DSLオプションとgradle.properties内のkotlin.coroutinesプロパティは非推奨になった。build.gradle(.kts)ファイルで、単にsuspend関数を使うか、kotlinx.coroutineの依存性を追加すること。
    Coroutineガイドでコルーチンについての知識を深める。

kotlin.parallel.tasks.in.projectビルドオプションの削除

Kotlin 1.5.20では、 kotlin.parallel.tasks.in.projectビルドオプションの非推奨がアナウンスされた。このオプションはKotlin 1.6.20で削除された。
プロジェクトによっては、Kotlinデーモンで並列コンパイルするのは、より資金が必要になるかもしれない。資金の浪費を減らすため、Kotlinデーモンのヒープサイズを増やすこと
Kotlin Gradleプラグインで、現在サポートされているコンパイラオプションについての知識を深める。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0