Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Kotlin Contracts #m3kt
Search
Taro Nagasawa
November 07, 2018
Programming
4
3.9k
Kotlin Contracts #m3kt
どこでもKotlin #6 で発表したスライドです
Taro Nagasawa
November 07, 2018
Tweet
Share
More Decks by Taro Nagasawa
See All by Taro Nagasawa
Android開発者のための Kotlin Multiplatform入門
ntaro
0
520
Kotlin 最新動向2022 #tfcon #techfeed
ntaro
1
2.2k
#Ubie 狂気の認知施策と選考設計
ntaro
13
13k
UbieにおけるサーバサイドKotlin活用事例
ntaro
1
1.1k
KotlinでSpring 完全理解ガイド #jsug
ntaro
6
3.4k
Kotlinでサーバサイドを始めよう!
ntaro
1
950
Androidからサーバーサイドまで!プログラミング言語 Kotlinの魅力 #devboost
ntaro
5
2.6k
How_to_Test_Server-side_Kotlin.pdf
ntaro
1
470
Kotlin Fest 2018 - Opening session
ntaro
0
4.2k
Other Decks in Programming
See All in Programming
2024年のkintone API振り返りと2025年 / kintone API look back in 2024
tasshi
0
220
お前もAI鬼にならないか?👹Bolt & Cursor & Supabase & Vercelで人間をやめるぞ、ジョジョー!👺
taishiyade
6
4k
color-scheme: light dark; を完全に理解する
uhyo
3
310
『テスト書いた方が開発が早いじゃん』を解き明かす #phpcon_nagoya
o0h
PRO
2
210
コミュニティ駆動 AWS CDK ライブラリ「Open Constructs Library」 / community-cdk-library
gotok365
2
120
How mixi2 Uses TiDB for SNS Scalability and Performance
kanmo
37
14k
ソフトウェアエンジニアの成長
masuda220
PRO
10
1.1k
技術を根付かせる / How to make technology take root
kubode
1
250
ファインディLT_ポケモン対戦の定量的分析
fufufukakaka
0
710
富山発の個人開発サービスで日本中の学校の業務を改善した話
krpk1900
4
390
ファインディの テックブログ爆誕までの軌跡
starfish719
2
1.1k
Introduction to kotlinx.rpc
arawn
0
700
Featured
See All Featured
The Power of CSS Pseudo Elements
geoffreycrofte
75
5.5k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Why Our Code Smells
bkeepers
PRO
336
57k
How GitHub (no longer) Works
holman
314
140k
Into the Great Unknown - MozCon
thekraken
35
1.6k
Unsuck your backbone
ammeep
669
57k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Writing Fast Ruby
sferik
628
61k
GraphQLの誤解/rethinking-graphql
sonatard
68
10k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.3k
BBQ
matthewcrist
87
9.5k
Music & Morning Musume
bryan
46
6.3k
Transcript
Kotlin Contracts 2018-11-07 長澤 太郎
長澤太郎 • @ngsw_taro • Ubie株式会社 ソフトウェアエンジニア • エムスリー エンジニアフェロー •
日本Kotlinユーザグループ代表
課題: 便利な関数があるのにスマートキャス トできない(Kotlin 1.3より前) val name: String? = user.name if
(!name.isNullOrBlank()) { println("Hello, ${name.capitalize()}") }
課題: 便利な関数があるのにスマートキャス トできない(Kotlin 1.3より前) val name: String? = user.name if
(!name.isNullOrBlank()) { println("Hello, ${name.capitalize()}") } stdlibの関数
課題: 便利な関数があるのにスマートキャス トできない(Kotlin 1.3より前) val name: String? = user.name if
(!name.isNullOrBlank()) { println("Hello, ${name.capitalize()}") } Nullableのため 禁止されている呼び出し
課題: 便利な関数があるのにスマートキャス トできない(Kotlin 1.3より前) val name: String? = user.name if
(!name.isNullOrBlank()) { println("Hello, ${name.capitalize()}") } val name: String? = user.name if (name != null && name.isNotBlank()) { println("Hello, ${name.capitalize()}") }
Kotlin 1.3 ではスマートキャストが効く! val name: String? = user.name if (!name.isNullOrBlank())
{ println("Hello, ${name.capitalize()}") } NotNullが保証されてるので 呼び出し可能
Contracts(契約) • 契約による設計/契約プログラミング • 事前条件 ◦ 関数を呼び出すための条件を利用者が満たす ◦ 例)型で不正な値を引数に取らせない ◦
例)require関数などで不正な値が渡ってきたら例外スロー • 事後条件 ◦ 関数を呼び出したあとの状況を関数が保証する ◦ 例)list#addしたらサイズは1増えることを保証する • 不変条件 ◦ オブジェクトが満たすべき状態を維持する ◦ 例)Nameオブジェクトは1字以上20字以下の英字を必ず持つ
Contracts(契約) • 契約による設計/契約プログラミング • 事前条件 ◦ 関数を呼び出すための条件を利用者が満たす ◦ 例)型で不正な値を引数に取らせない ◦
例)require関数などで不正な値が渡ってきたら例外スロー • 事後条件 ◦ 関数を呼び出したあとの状況を関数が保証する ◦ 例)list#addしたらサイズは1増えることを保証する • 不変条件 ◦ オブジェクトが満たすべき状態を維持する ◦ 例)Nameオブジェクトは1字以上20字以下の英字を必ず持つ Kotlin Contractsはここ しかも静的
契約を表明するDSL val name: String? = user.name if (!name.isNullOrBlank()) { println("Hello,
${name.capitalize()}") } inline fun CharSequence?.isNullOrBlank(): Boolean { contract { returns(false) implies(this@isNullOrBlank != null) } return this == null || this.isBlank() }
契約を表明するDSL val name: String? = user.name if (!name.isNullOrBlank()) { println("Hello,
${name.capitalize()}") } inline fun CharSequence?.isNullOrBlank(): Boolean { contract { returns(false) implies(this@isNullOrBlank != null) } return this == null || this.isBlank() }
契約を表明するDSL val name: String? = user.name if (!name.isNullOrBlank()) { println("Hello,
${name.capitalize()}") } inline fun CharSequence?.isNullOrBlank(): Boolean { contract { returns(false) implies(this@isNullOrBlank != null) } return this == null || this.isBlank() } falseが返されるとき、この文字列はNotNullであることを意味する
自分の関数にも契約を @ExperimentalContracts fun Any?.isNotNull(): Boolean { contract { returns(true) implies
(this@isNotNull != null) } return this != null }
自分の関数にも契約を @ExperimentalContracts fun Any?.isNotNull(): Boolean { contract { returns(true) implies
(this@isNotNull != null) } return this != null } DSL自体は不安定 バイナリ互換は維持される
契約対応している標準関数 kotlin.testも含む • assertTrue • check • require • assertFalse
• assertNotNull • checkNotNull • requireNotNull 引数がtrueを保証 引数がfalseを保証 引数がNotNullを保証
課題: val変数の初期化が絶対に成功するはず なのにできない(Kotlin 1.3より前) val x: Int run {
x = 12345 } println(x) ラムダの中での初期化を コンパイラはわかってくれ ない
Kotlin 1.3では「1度だけ呼び出される」契約によ り初期化OK val x: Int run { x =
12345 } println(x)
契約を表明するDSL val x: Int run { x = 12345 }
inline fun <R> run(block: () -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() }
契約を表明するDSL val x: Int run { x = 12345 }
inline fun <R> run(block: () -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() }
契約を表明するDSL val x: Int run { x = 12345 }
inline fun <R> run(block: () -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() } blockが「ちょうど1度だけ」呼び出される
InvocationKind • AT_MOST_ONCE • EXACTLY_ONCE • AT_LEAST_ONCE • UNKNOWN
契約対応している標準関数 kotlin.testも含む • run • with • apply • also
• let • takeIf • takeUnless • repeat EXACTLY_ONCE UNKNOWN
契約DSLまとめ • contract: 関数の先頭に置く必要がある • returns(): 関数の実行が成功したら... • returns(Any?): 引数の値
true|false|null を返したら... • returnsNotNull(): NotNullを返したら... • callsInPlace: 引数の関数が呼ばれる回数を保証 contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } contract { returns(true) implies (arg != null) }
総まとめ • スマートキャストや変数初期化において、面倒なことがあった けどKotlin 1.3で解消された • 契約DSLで契約を表明することでコンパイラに意味が伝わる • 自分の関数に契約DSLを使うことができるが不安定 •
標準ライブラリ関数で契約DSLを使っているものがあるが安 定 • バイナリ互換あり