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
4.3k
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
1.1k
Kotlin 最新動向2022 #tfcon #techfeed
ntaro
1
2.3k
#Ubie 狂気の認知施策と選考設計
ntaro
13
13k
UbieにおけるサーバサイドKotlin活用事例
ntaro
1
1.2k
KotlinでSpring 完全理解ガイド #jsug
ntaro
6
3.6k
Kotlinでサーバサイドを始めよう!
ntaro
1
1k
Androidからサーバーサイドまで!プログラミング言語 Kotlinの魅力 #devboost
ntaro
5
2.9k
How_to_Test_Server-side_Kotlin.pdf
ntaro
1
530
Kotlin Fest 2018 - Opening session
ntaro
0
4.3k
Other Decks in Programming
See All in Programming
re:Invent 2025 のイケてるサービスを紹介する
maroon1st
0
160
從冷知識到漏洞,你不懂的 Web,駭客懂 - Huli @ WebConf Taiwan 2025
aszx87410
2
3.3k
PostgreSQLで手軽にDuckDBを使う!DuckDB&pg_duckdb入門/osc25hi-duckdb
takahashiikki
0
230
今こそ知るべき耐量子計算機暗号(PQC)入門 / PQC: What You Need to Know Now
mackey0225
3
200
これならできる!個人開発のすゝめ
tinykitten
PRO
0
150
AI時代を生き抜く 新卒エンジニアの生きる道
coconala_engineer
1
520
AIエージェントの設計で注意するべきポイント6選
har1101
6
3k
Implementation Patterns
denyspoltorak
0
150
GoLab2025 Recap
kuro_kurorrr
0
2.6k
脳の「省エネモード」をデバッグする ~System 1(直感)と System 2(論理)の切り替え~
panda728
PRO
0
130
生成AIを利用するだけでなく、投資できる組織へ
pospome
2
440
クラウドに依存しないS3を使った開発術
simesaba80
0
220
Featured
See All Featured
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
For a Future-Friendly Web
brad_frost
180
10k
Unsuck your backbone
ammeep
671
58k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
0
2.3k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
3.3k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
74
Crafting Experiences
bethany
0
26
The Power of CSS Pseudo Elements
geoffreycrofte
80
6.1k
Building Applications with DynamoDB
mza
96
6.9k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.1k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
420
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.2k
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を使っているものがあるが安 定 • バイナリ互換あり