Kotlin 1.6.20
日付:2022/03/09
URL:https://blog.jetbrains.com/kotlin/2022/02/kotlin-1-6-20-m1-released/
調査者:Mori Atsushi, mayamito, Go, saku, chigichan24
カテゴリ:Kotlin, Kotlin 1.6
一言で表すと
概要
Prototype of context receivers for Kotlin/JVM
以前の調査: Prototype multiple receivers
YouTrackで結構いい反応があったから作った
https://youtrack.jetbrains.com/issue/KT-10468
バックグラウンド
YouTrackから抜粋してみる
サードパーティライブラリの独自クラスを拡張するのは結構たいへんだよね。
例えば Android View の中で動く Floatの拡張関数 dp みたいなものを作ろうとすることとか
Mori Atsushi.icon 今まさに地獄が起きている
code:kotlin
import androidx.compose.ui.dp as composeDp
import com.sample.util.dp as viewDp
"XXのなかで動く(XXを拡張する)"というコンテキストを持った状態の拡張関数がほしい。
現在はある一つのcontextについてはできる
code: kotlin
interface Entity
interface Scope { // Scope is a dispatch receiver
fun Entity.doAction() { // Entity is an extension receiver for doAction
...
}
}
with(scope) { // 拡張関数
entity.doAction()
}
しかし、複数のContextに対応し、もっと(top-levelのものにも)簡単に適用したい、簡単な記述で実現したい
KEEPのほうにもっと詳細が書いてある
https://github.com/Kotlin/KEEP/blob/context-receivers/proposals/context-receivers.md
サンプル
code: kotlin
interface LoggingContext {
val log: Logger // This context provides a reference to a logger
}
context(LoggingContext)
fun startBusinessOperation() {
// You can access the log property since LoggingContext is an implicit receiver
log.info("Operation has started")
}
fun test(loggingContext: LoggingContext) {
with(loggingContext) {
// You need to have LoggingContext in a scope as an implicit receiver
// to call startBusinessOperation()
startBusinessOperation()
}
}
takahiromさんのツイート
https://twitter.com/new_runnable/status/1491214603451510785/photo/1
Fragmentのスコープでのみ使うことができるStateFlowのobserve拡張関数
オンにするには
コンパイラオプション、-Xcontext-receivers を指定してね。
Mori Atsushi.icon デフォルトになる未来、こわい…
Mori Atsushi.icon 有効でないプロジェクトから見ると、どうなるんだろう?
当然まだ experimental な機能なので、IDEのサポートとかは弱い
なんかあったらここで報告して〜と言っているがぜんぜん議論はされてない...
https://youtrack.jetbrains.com/issue/KT-42435
Mori Atsushi.icon 今までの拡張関数の表記とどっちが推奨なんだろう?
Mori Atsushi.icon 命名とかかぶったらどうなるんだろう?
code:kotlin
context(LoggingContext)
fun startBusinessOperation() { /* */ }
context(OtherContext)
fun startBusinessOperation() { /* */ }
fun LoggingContext.startBusinessOperation() { /* */ }
mayamito.icon どんなJavaのバイトコードが吐き出されるのか
Mori Atsushi.icon 複数の引数で呼び出せそう?
chigichan24.icon takahirom さんの例の話
https://twitter.com/new_runnable/status/1491319602378584067
code: java
public static final void observe(@ NotNull final Fragment var0, @ NotNull final StateFlow $ this$observe, @ NotNull final Function1 block)
メモ
stableにはだいぶ時間かかるのでは?
inline class / value classみたいに永遠にexperimentalな可能性もありそう
記法が変わる可能性がありそう
Support for parallel compilation of a single module in the JVM * backend
単一モジュールの並列コンパイル
Kotlin 1.6.20-M1ではモジュール内の全てのファイルを並列にコンパイルするIRバックエンドモードが追加された
コンパイル時間を最大で15%短縮できるらしい
KT-46768
インライン関数を多用するプロジェクトだとパフォーマンスがよくなかった?修正された。
KT-41510
コンパイラオプション -Xbackend-threadsで有効にできる
引数
N→スレッド数。指定しないとスレッド間でコンテキストが失われて、並列化の効果が失われる。
0と入れると、各CPUに1つのスレッドを使う
Go.icon Nはコンテキストを共有して実行したいスレッド数ってこと?(よくわからない)
この並列化は、Gradleなどのビルドツールでビルドが十分に並列化していない場合のみ役立つ。
非常に大きな1つのモジュールがあれば効果があるかも
KT-46085
chigichan24.icon この問題に敏感な組織は既にマルチモジュール化してそう...
一方で、たくさんの小さなモジュールでやると、並列化のレイヤーが一つ追加されて、コンテキストスイッチのためにパフォーマンスが低下する可能性がある。
Go.icon 元々マルチモジュールになっているプロジェクトには有効じゃないかも
kaptはIRバックエンドを無効にするので、この並列化コンパイルはうまくいかないことに注意する
Go.iconモジュールが一個しかないAndroidプロジェクトなら有効かなと思ったけど、kaptでうまくコンパイルできないなら有効にするのは厳しそう😅
chigichan24.icon 悲しい
設計上、並列化コンパイルはより多くのJVMヒープを必要とすることに注意する
ヒープ量はスレッド数に比例する
Incremental compilation for development binaries with Kotlin/JS IR compiler
Kotlin/JSのより効率的な開発のための新しいインクリメンタルコンパイルモード
GradleのcompileDevelopmentExecutableKotlinJsタスクでdevelopビルドをする場合、このモードではコンパイラが前回のコンパイル結果をモジュールレベルでキャッシュし、それを利用する。
edit-build-debugサイクルの高速化
本番ビルドには影響しないことに注意
インクリメンタルコンパイルモードを有効にするには、gradle.propertiesファイルに以下を追記する。
code:gradle.properties
kotlin.incremental.js.ir=true // false by default
mayamito.icon run系のタスクでも使えると-tオプション (--continuousオプション)と組み合わせられてよさそうだけどどうなんだろ?
Hierarchical structure support for multiplatform projects
Kotlin 1.4.0で導入された、KMPで階層的にプロジェクトを設定できるやつがデフォルトで有効になった
code:kotlin
kotlin{
sourceSets {
val desktopMain by creating {
dependsOn(commonMain)
}
val linuxX64Main by getting {
dependsOn(desktopMain)
}
val mingwX64Main by getting {
dependsOn(desktopMain)
}
val macosX64Main by getting {
dependsOn(desktopMain)
}
}
}
以前の調査:Share code on platforms
プロジェクトでの利点
Foundation、UIKit、POSIXなどのプラットフォーム依存ライブラリを使用できるようになる
windows用のコードをmacOSのコードで使うことがなくなる
ライブラリでの利点
各プラットフォームで適切なAPIを公開しやすくなる
Kotlin Coroutinesのプロジェクトの例
https://scrapbox.io/files/62289c9aa6fad5001d5970ee.png
使い方
すでにgradle.propertiesで手動でONにしてる場合はそのオプションを消せる
code:groovy
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false
Android Studio 2021.1.1(Bumblebee)以降を使用するのがおすすめ
Mori Atsushi.icon なにか機能がある?
Mori Atsushi.icon 気になったこと
なにかいつの間にかtarget増えてない?
Android NDK
androidNativeArm32
androidNativeArm64
androidNativeX86
androidNativeX64
iOS
iosSimulatorArm64(AppleSiliconプラットフォーム上のAppleiOSシミュレーター)
tvOS
tvosArm64
tvosSimulatorArm64
macOS
macosArm64
WebAssembly
wasm32
https://kotlinlang.org/docs/multiplatform-dsl-reference.html#targets
Kotlin/Native performance improvements
Kotlin/Nativeのコンパイル高速化を頑張ってる
https://youtrack.jetbrains.com/issue/KT-42294
1.6.20では... LLVM IRに影響するアップデートとバグ修正が行われた
平均して次のようなパフォーマンス向上が得られる
execution timeを15%削減
mayamito.icon 昔同じコードをJVM, JS, Nativeで動かして比較したらNativeが一番遅かったのでこれは嬉しい
releaseとdebug両方のバイナリサイズを 20%削減
releaseバイナリのコンパイル時間を26%削減
どうやって実現しているか
コンパイラによって生成された合成オブジェクト(synthetic objects)の一部に、静的初期化を実装
全ての関数のLLVM IRの構造を改善
コンパイラキャッシュを最適化
どうやって効果を確認するか
Kotlin 1.6で新しいメモリマネージャーが発表されているので、これを使う
https://kotlinlang.org/docs/whatsnew16.html#preview-of-the-new-memory-manager
chigichan24.icon きになる。永遠にこの話してる気がする。
https://blog.jetbrains.com/kotlin/2021/08/try-the-new-kotlin-native-memory-manager-development-preview/
-Xgc=cms で新しいメモリマネージャーを有効化できる
何か問題が起きたら
ここにフィードバックする https://youtrack.jetbrains.com/issue/KT-48526
気になるポイント
メモ
コメント