# Kotlin Fest 2019 ## Coroutinesを理解しよう コルーチンとはなにか - メルビン・コンウェイの論文→Simulaで実装 - たくさんの言語でたくさんの実装(抽象に対する実装は色々ある) 中断と再開を普通の関数に入れる!もの. →コルーチン同士で協調的に動作する(対象) しかし,これはかんりが大変なので,非対称コルーチン(親子関係がある)も登場. ### 嬉しいこと - 継続状況をひょうげんしやすい - 継続状況とは,コールバックで帰ってきて実行する処理のこと - 中断と再開を表現できるから - スレッドより軽量 - ThreadPool使うより軽量(同じスレッドでいくつか動けるので) ### Kotlinでの実装 `suspend`キーワードをつけた関数はコルーチンで実行される. このキーワードを付けられた関数はlaunch関数のなかで実行できる ここまでコンパイラ 此処から先,実行,キャンセル...etcは標準ライブラリが行っている ### コルーチンスコープ スコープにもライフサイクルがあって,スコープが閉じると中のコルーチンが全部落ちる ### ブロッキング runBlockingを使うとコルーチンをブロッキングに実行可能 runBlockingのthisはCoroutineScopeなので,そこでthis.launchを呼び出せれば子コルーチンになる→待ち合わせが可能 ### キャンセル launch関数の返り値はJobなので,これを使ってcancelできる ### 実行コンテキスト withContextを使うと,実行コンテキストを変えられる コルーチンディスパッチャーの実装を渡す ### 例外のハンドリング try-catchで囲むだけで良い ### コルーチンスコープと構造化された並行性 suspend関数を立てに並べると順次(ブロッキングに)実行される →同時に動かしたい場合は,asyncを使って同時に待ち合わせる?→awaitを使うと待ち合わせ これ全体をtry-catchで囲むとクラッシュするらしいw 分岐と合流の範囲を明示的に宣言する! →コルーチンスコープをたくさん作って構造化して,処理のまとまりを作ろう!(親子関係) viewModelScopeをtry-catchで囲めばいいのでは?とか思ったw ### コルーチンと設計 - コルーチンスコープとアプリケーションライフサイクルを合わせる - プロセスはGrobal Scope - Activity,FragmentはlifecycleScope - viewModelはviewModelScope - LiveDataはlivedtaScope - suspend関数はメインセーフティで作る - 呼び出し元がメインスレッドだったとしても問題ないように実装しよう! - IOはDispatcher.IOでやるとか - コルーチンはメインセーフティで実装する - launchの中でメインスレッド出ない可能性を考えない構造のほうが良い ### テスト suspend関数をテストするときはrunBlocking 間接的にコルーチンを起動するとき, 単純に完了を待つ場合はメインセーフティで呼び出してテストスレッドで呼び出すようにする(Main以外のディスパッチャをsuspend関数はディスパッチャをインジェクトする仕組みを提供する必要がある!!!) 実行タイミングを制御したい場合は,上に加えて更にrunBlockingTestのテストルールを書くしかない.テスト実行中に使うディスパッチャを指定する.あとは,うまく関数をモックして待ってもらうようにする.あまりイケてない kotlinx-coroutines-testというライブラリが公式で出てる runBkockingTestとかができる ## 改めて学ぶKotlin Contracs Dukat:TypeScriptの型定義をKotlinにしてくれるものらしい.闇の技術だ・・・ 意識せずとも使っているContracs ### Contracsとは? コンパイラにコンパイル時の制限をつけることができる様になる機能 静的解析できる,関数に適用できる. 1.3で導入.Experimental.現時点での構文はEarly Prototype なのに標準ライブラリでも使われてるw DSLと契約を結ぶことで条件を指定できる 現段階では26の標準関数のメソッドに使用. ### なぜできた? 時々コンパイラはいくつかの言語構造に過度な制限をつけてしまう. - ラムダでvalの定義ができない - キャプチャされた変数に対するスマートキャストは禁止 1.2ではrunの中でvalの初期化ができてなかったが,1.3ではできるようになった. requireもcontractsでスマートキャストとかできる プログラマの知ってる情報をコンパイラと契約することによって伝える! ### 契約について オブジェクト指向入門に契約の定義が書いてある. 達人プログラマーにも書いてある > 契約はあなと他の当事者の間にある権利と責任を定義するもの??? JetBrains社が提供してるContacts以外の契約を調べてみた `@Contract`アノテーション > 契約とは,入力と出力を記述する句の集合 この関数は関数の型を明示的につけられて,それと静的解析の結果が違うと警告が出るたぐいのものらしい はじめはこれを改造する予定だったらしい. ただし, - Kotlin対応の難しさ - IDE側の静的解析ツールの改修が必要 - コンパイルエラーにならない - 嘘をつける により,この方法は見送られた ### とりあえず触ってみよう 関数がContractを持つ. ContractはEffectの集まりになっている. これをラムダ形式で記述できる Experimentalなのでアノテーションを付ける必要がある Effectはたくさんある. - CallsInPlace - 関数が何回呼ばれるか - ConditionnalEffect - nullかどうかとか - SimleEffect スマートキャストに使えたりする 利用できないケース - 契約を関数のはじめに置かなかった場合 - トップレベルの関数ではない場合 - 関数ブロック内でない場合 - プロパティのgetter/setterに定義する場合 - 効果が指定されてない場合 - if/whenブロックをcontratsブロック内で使う場合 ### 今後のサポートは? - 変更があるかもしれない - ただし,1.4.0を目標にしたIssueがいくつかあるので,Deprecatedになることはなさそう - 規模感的にはInline classと同等くらいの勢いがあってよろしい ### プロトタイプ demiurg906さんがcontracts-sampleを公開している https://github.com/demiurg906/kotlin-contracts-samples/ プロトタイプなので独自の関数,契約がたくさん入っている(そもそもIDEのKotlin pluginがforkされたものなので,導入コスト高そうw) ## Kotlin MPP入門 AAkiraさん 去年からKotlin MPP使ってプロダクト開発とかしてたらしい timber LikeなKotlin MPP用ライブラリとしてNapierというログライブラリ作ったらしい ### クロスプラットフォームの歴史 アプローチほうほうはいくつか存在 - UI含む全てのコードを共有(独自UI - Flutter - UIは共通化(ネイティブ - ReactNativeとか - ロジックのみ - Java2Obj - Xamarin - Kotlin MPP Kotlin MPPはUIは共通化せずに,ロジックだけ共通化する Jetpack Composeとか使えば全部できるのではと言われているが,Googleの人曰くそうで花らしい. ### Kotlin MPPとは Android, Native, JS, JVMの4環境に対応する MPPは公式らしい. 2012年にはもうすでにJSに関する記述がる! Jetbransのやる気はすごい Effective multiplatform Kotlin developmentという発表で実用できな使い方を実践してるらしい ### プロダクトごとの説明 - Kotlin/JVM - Kotlin/Native - LLVMToolchainを使って各プラットフォームのバイナリを作成 - iOS,MacOS,Android NDK,Linux,WebAssemblyに対応アーキテクチャも順次対応 - Kotlin NativeのバージョンはKotlin本体のバージョンと統合された - プリミティブ型はそれぞれキャスト可能 - Kotlinのトップレベル関数はファイル名Ktクラスの中に入る - まだ互換性に難あり - Freezeされていないオブジェクトは別スレッドで操作不可 - すでにFreezeされているオブジェクトもあるが,自作した場合はFreezeを明記する - Kotlin.JS - DOMも操作可能 - JavaScriptにすると型情報は死ぬ - TypeSCript対応も考えられているらしい - nullチェックとかはやってくれる - ライブラリの読み込みも可能→external週初期を付与して外部のライブラリの型情報を記述する必要がある - dynamic型:Kotlin側でJSの型がわからないばあいに使用されるAny?みたいなもの - JSの種類も指定できる ### メリデメ メリット - これまでもマルチプラットフォームはあったが,置き換えはできてない - 一つのコードでUIが共通化されてしまう子のが問題? - →MPPはUIが共通化しないので良い?また,外部ライブラリとしての導入も可能 - MPPはネイティブアプリと同じ言語でかける! - 従来はiOSとAndroidの共通化を思想として持っていたが,MPPは全部共通化しようとしてる - ドメインオブジェクトを共通化できる・・・!(確かにこれはでかい) - ロジックの共通化ができるので,同じことをなんかも書く必要がなくなる - 認証系 - ログ送信基盤 - 広義のUtilityを共通化 デメリット - Javaのしさんが使えない - もしかしたら対応するかも - iOSでCoroutineがメインスレッドしか使えない - .frameworkを1つしか読み込めない - ライブラリのKotlin versinoを揃えないといけない - 他の環境のエンジニアのり変えを得ないとだめ ### 仕組み 共通モジュールで生成された成果物を書くプラットフォームから参照する 作り方 - 共通モジュール作成(common) - Gradleの設定 - プラグイン入れるだけ すべての共通化は難しい. - expectとactualで問題を解決(抽象と具象) - classだけじゃなくて関数とかにも使える - 読み込んだプラットフォーム全てに実装がないと怒られるようになってる ライブラリの選定 - ktor - Kotlin selialization - SQL delight - multiplatform-settings - kodein - kotlin io - klock - napier Kotlin-Multiplatform-librariesというリポジトリでまとめてくれている ### 設計を考える クライアントはMVPが推奨されている. サーバはKtor一度 - BFFをMPPで作るときれいになるらしい ### 実際の作り方 Gradleファイルは1プラグイン,1ファイル構成が正しい Androidの設定はAndroid用の別ファイルに分割してincludeするよ良い kotlin{}の中では環境を示す関数を呼び出すだけ.iOSだけ特殊で,実行環境を見て場合分けが必要. プラグインの名前が依存関係の名前のプレフィックスになる→iOSの場合はiOSと指定し直したほうがわかりやすい Gradleプロジェクトから読み出せる普通のライブラリを作っているような感覚で開発ができる!!! ### 呼び出し側 iOSでマルチスレッドする場合は,呼び出すときに別スレッドで呼び出すようにして,MPPではマルチスレッド使用不可能問題に対応する mpp-exampleリポジトリが存在 本が出るっぽい MPPのことが書かれた ## Deep Dive Into Kotlin DSL Domain Specific Language 特定の目的だけに用いられる言語 - 難しいコードをかんたんに表現することができる - 読み書きかんたんん - 小さいAPI,ドメイン - 人間のミスを少なくできる - 型システム 例えば,Ktorで使われてるhtml {}とかみたいな感じ - External DSL - SQL,CSS,正規表現 - Internal DSL - HTML,モックライブラリ,DIコンテナ - Kotlin DSL Internal DSLは汎用プログラム言語によることがおおい ### テクニック - 入門レベル - 言語仕様 - 型システム(性的型付け,静的解析可能) - ラムダ式: 関数型かSAMの糖衣構文 - 関数リテラルとレシーバー - 中級 - 拡張関数 - 演算子のオーバーロード - htmlのときに+を使ってcontentを記述する的な - infix修飾子:これは似引数関数を中興できるやつだ - Gradleでdebugとかを書くときにcreate()とかするけど,これはKotlinでは動的にdebugを設定できないからで,それをやるものをcreate()で作っているらしい.更にconfigureをinvokeで設定することで,configureをDSLの使用者から見えないようにしている - 移譲: SharedPreferencesは低レベルなAPIで使いづらい.Kotprefを使うと,DSLにSharedElementを使える, - 移乗を使ってDRYになる - 難しい - samwithreceiverのテーションを使うとSAM-with-revieverが用意に実現可能 - DslMarker:headタグの中にheadタグはいいってはいけないけど普通に作ると入っちゃう.DslMarkerを使うと制限を書ける.しかもコンパイルエラーになるらしい - コンパイラプラグインはドキュメント化されてない ### クイックtips APIとDSLの違い - DSLはドメインに着目 - DSLはドメインに特化したAPI群と言える もともと存在するライブラリにDSLをつけることが可能. そうなってくると,DSLとJVM言語との対応が気になる Java -> Kotlin DSL:これは困らない. Kotlin DSL -> Java - メソッドチェーンで提供する - インライン関数は使えない Martin FowlerのDSLのドキュメントを読むと良い. Kotlin DSLはAPIの一つの形.むずかしくない ## Kotlin/Nativeはなぜ動くのか サーバサイドエンジニアの人,19新卒らしい ### Kotlin/Nativeとは 各プラットフォーム向けのバイン理生成 Cとの相互運用機能 Obj-CとSwiftとの相互運用機能 が備わっている ### なぜ動くのか Runtime - 標準ライブラリ,メモリ管理モジュールなど - もともJVM言語だったので,メモリ管理や標準ライブラリはJVMがやってくれれていた 標準ライブラリ - 1から実装 - C++による - 2パターンの実装方法 - Kotlinのみで実装(ranged,coroutines) - 本体の実装はC++で行う: 無理ミティ部型,printなどのIO - externalとSymbokNameアノテーション(関数の実装のシンボル名(C**での関数名))をつける メモリ管理 - GCがちゃんと行われるらしい - C++で実装されている. - 外部ライブラリとして,Cのライブラリを使うとGCは使えない プログラムランチャー - GC初期化 - プログラム起動 - プラットフォームによって異なる起動方法をいい感じに吸収してくれる - Konan_run_start()で吸収してるっぽいな プラットフォームライブラリ - platform.*なパッケージ名 - POSIXのシステムコールのラッパー関数が呼び出せたりするっぽい - CInterupを使っている - .defファイルにパッケージ名,変換するヘッダ一覧,コンパイラ引数を指定するとスタブが生成される. ### Kotlinはどのようにしてネイティブバイナリになるのか kotlinc-native -Xlist-phasesを使うと,流れが見える 出力されるログは,下に行くほどネイティブになってる →4のフェーズが重要らしい Frontend Phase - KotlinのコードをASTにする(PSIという形式になってるらしい) Psi2IR Phase - ASTをKotlin-IR(中間言語)に変換する LLVMについて - コンパイラのためのフレームワークのようなもの. - LLVM-IRという中間言語があり,これに対するコンパイラを書くだけで,バイナリコードの生成が可能になっている Backend Phase - Kotlin-IRをLLVM-Bitcode(LLVM-IRのバイナリ形式)に変換する - .kt.bcというバイナリが生成される.(1MBくらい) Linker Phase - リンカが頑張るフェーズ - オブジェクトファイルの生成はclangがやってるらしいw - リンカはいつものlt