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.1k
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
720
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
990
Androidからサーバーサイドまで!プログラミング言語 Kotlinの魅力 #devboost
ntaro
5
2.8k
How_to_Test_Server-side_Kotlin.pdf
ntaro
1
500
Kotlin Fest 2018 - Opening session
ntaro
0
4.3k
Other Decks in Programming
See All in Programming
中級グラフィックス入門~効率的なメッシュレット描画~
projectasura
4
2.2k
MySQL9でベクトルカラム登場!PHP×AWSでのAI/類似検索はこう変わる
suguruooki
1
270
Git Sync を超える!OSS で実現する CDK Pull 型デプロイ / Deploying CDK with PipeCD in Pull-style
tkikuc
4
490
Flutterと Vibe Coding で個人開発!
hyshu
1
190
LLMは麻雀を知らなすぎるから俺が教育してやる
po3rin
3
1.6k
Amazon Q CLI開発で学んだAIコーディングツールの使い方
licux
3
140
Advanced Micro Frontends: Multi Version/ Framework Scenarios
manfredsteyer
PRO
0
130
JetBrainsのAI機能の紹介 #jjug
yusuke
0
160
抽象化という思考のツール - 理解と活用 - / Abstraction-as-a-Tool-for-Thinking
shin1x1
1
900
Prompt Engineeringの再定義「Context Engineering」とは
htsuruo
0
110
AIのメモリー
watany
12
1.2k
AIに安心して任せるためにTypeScriptで一意な型を作ろう
arfes0e2b3c
0
310
Featured
See All Featured
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
A designer walks into a library…
pauljervisheath
207
24k
Git: the NoSQL Database
bkeepers
PRO
431
65k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
29
9.6k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
8
730
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
1k
Reflections from 52 weeks, 52 projects
jeffersonlam
351
21k
The Power of CSS Pseudo Elements
geoffreycrofte
77
5.9k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Bash Introduction
62gerente
613
210k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
15
1.6k
A Tale of Four Properties
chriscoyier
160
23k
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を使っているものがあるが安 定 • バイナリ互換あり