Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ContractsでCompilerを賢くしよう / love_kotlin #5
Search
star_zero
October 24, 2018
Programming
2
640
ContractsでCompilerを賢くしよう / love_kotlin #5
star_zero
October 24, 2018
Tweet
Share
More Decks by star_zero
See All by star_zero
今からはじめるAndroidアプリ開発 2024 / DevFest 2024
star_zero
0
1.5k
Jetpack Compose の Side-effect を使いこなす / DroidKaigi 2023
star_zero
5
6.6k
Android 14 新機能 / Android 14 Meetup Nagoya
star_zero
1
630
Android 14 と Predictive back gesture / Shibuya.apk #42
star_zero
0
430
Coroutines Test 入門 / Android Test Night #8
star_zero
2
1.2k
What's new in Jetpack / I/O Extended Japan 2022
star_zero
1
670
Kotlin 2021 Recap / DevFest 2021
star_zero
3
1.3k
Kotlin Symbol Processing (KSP) を使ったコード生成 / DroidKaigi 2021
star_zero
2
5.2k
What's new Android 12
star_zero
0
580
Other Decks in Programming
See All in Programming
組み合わせ爆発にのまれない - 責務分割 x テスト
halhorn
1
140
AWS CDKの推しポイントN選
akihisaikeda
1
240
從冷知識到漏洞,你不懂的 Web,駭客懂 - Huli @ WebConf Taiwan 2025
aszx87410
1
1.3k
Socio-Technical Evolution: Growing an Architecture and Its Organization for Fast Flow
cer
PRO
0
320
JETLS.jl ─ A New Language Server for Julia
abap34
1
310
Cell-Based Architecture
larchanjo
0
110
ゲームの物理 剛体編
fadis
0
320
「コードは上から下へ読むのが一番」と思った時に、思い出してほしい話
panda728
PRO
38
25k
React Native New Architecture 移行実践報告
taminif
1
150
STYLE
koic
0
160
DSPy Meetup Tokyo #1 - はじめてのDSPy
masahiro_nishimi
1
160
AIコーディングエージェント(skywork)
kondai24
0
150
Featured
See All Featured
Java REST API Framework Comparison - PWX 2021
mraible
34
9k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.8k
We Have a Design System, Now What?
morganepeng
54
7.9k
What's in a price? How to price your products and services
michaelherold
246
12k
Balancing Empowerment & Direction
lara
5
790
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Designing for humans not robots
tammielis
254
26k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.8k
The Art of Programming - Codeland 2020
erikaheidi
56
14k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
970
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Transcript
Contractsで Compilerを賢くしよう Kotlin愛好会 vol5
About me •Kenji Abe •Cookpad Inc. •Android Developer •Twitter: @STAR_ZERO
Contracts •Kotlin 1.3の新機能 •関数の動作を明示的にCompilerへ伝える •スマートキャストをより便利に
今回の環境 •IntelliJ IDEA 2018.2.5 •Kotlin 1.3.0-rc-190
簡単な例
Contractsなし fun isNonNull(s: String?): Boolean { return s != null
} fun hoge(s: String?) { if (isNonNull(s)) { // Smart CastされないのでCompile Error println(s.length) } }
Contractsあり @ExperimentalContracts fun isNonNull(s: String?): Boolean { contract { returns(true)
implies (s != null) } return s != null }
Contractsあり @ExperimentalContracts fun hoge(s: String?) { if (isNonNull(s)) { //
Smart Castしてくれる println(s.length) } }
Contractsなし fun runFunc(func: () -> Unit) { func() } fun
hoge() { var x: Int runFunc { x = 10 } // Variable 'x' must be initialized println(x) }
Contractsあり @ExperimentalContracts fun runFunc(func: () -> Unit) { contract {
callsInPlace(func, InvocationKind.EXACTLY_ONCE) } func() }
Contractsあり @ExperimentalContracts fun hoge() { var x: Int runFunc {
x = 10 } // エラーなし println(x) }
returns - implies
returns - implies @ExperimentalContracts fun isNonNull(s: String?): Boolean { contract
{ returns(true) implies (s != null) } return s != null } •戻り値によって決まる引数またはthisの状態を定義
returns - implies •returns() •returns(value: Any?) ‣ true, false, null
•returnsNotNull()
returns - implies •implies ‣ == null, != null ‣
is, !is
Example 1 @ExperimentalContracts fun validate(s: String?) { contract { returns()
implies (s != null) } if (s.isNullOrEmpty()) { throw IllegalArgumentException() } }
Example 1 @ExperimentalContracts fun hoge(value: String?) { validate(value) println("length =
${value.length}") }
Example 2 @ExperimentalContracts fun isString(v: Any?): Boolean { contract {
returns(true) implies (v is String) } return v is String }
Example 2 @ExperimentalContracts fun hoge(v: Any?) { if (isString(v)) {
println("length = ${v.length}") } }
Example 3 @ExperimentalContracts fun castInt(v: Any?): Int? { contract {
returnsNotNull() implies (v is Int) } return v as? Int }
Example 3 @ExperimentalContracts fun hoge(v: Any?) { if (castInt(v) !=
null) { println("${v + v}") } }
Example 4 @ExperimentalContracts fun Any?.isString(): Boolean { contract { returns(true)
implies (this@isString is String) } return this is String }
Example 4 @ExperimentalContracts fun hoge(v: Any?) { if (v.isString()) {
println("length = ${v.length}") } }
Example 5 @ExperimentalContracts fun stringOrInt(v: Any?) : Boolean { contract
{ returns(true) implies (v is String) returns(false) implies (v is Int) } return v is String }
Example 5 @ExperimentalContracts fun hoge(v: Any?) { if (stringOrInt(v)) {
println("length = ${v.length}") } else { println("plus = ${1 + v}") } }
callsInPlace
callsInPlace @ExperimentalContracts fun runFunc(func: () -> Unit) { contract {
callsInPlace(func, InvocationKind.EXACTLY_ONCE) } func() } •引数の関数が何回実行されるか
callsInPlace •AT_MOST_ONCE ‣ 1回実行されるか、呼び出されない •AT_LEAST_ONCE ‣ 1回以上呼び出される •EXACTLY_ONCE ‣ 1回だけ呼び出される
•UNKNOWN ‣ 呼び出される回数が不明
Example 1 @ExperimentalContracts fun runAtLeastOnce(func: () -> Unit) { contract
{ callsInPlace(func, InvocationKind.AT_LEAST_ONCE) } func() }
Example 1 @ExperimentalContracts fun hoge() { var x: Int runAtLeastOnce
{ x = 10 } println(x) }
Example 2 @ExperimentalContracts fun runAtMostOnce(func: () -> Unit) { contract
{ callsInPlace(func, InvocationKind.AT_MOST_ONCE) } func() }
Example 2 @ExperimentalContracts fun hoge() { var x: Int runAtMostOnce
{ x = 10 } // Variable 'x' must be initialized println(x) }
Example 3 @ExperimentalContracts fun runFuncs(func1: () -> Unit, func2: ()
-> Unit) { contract { // func1だけ設定 callsInPlace(func1, InvocationKind.EXACTLY_ONCE) } func1() func2() }
Example 3 @ExperimentalContracts fun hoge() { var x: Int runFuncs({
x = 10 }) { x = 20 } // Variable 'x' must be initialized println(x) }
Example 4 @ExperimentalContracts fun runFuncs(func1: () -> Unit, func2: ()
-> Unit) { contract { // 今度はfunc2だけ設定 callsInPlace(func2, InvocationKind.EXACTLY_ONCE) } func1() func2() }
Example 4 @ExperimentalContracts fun hoge() { var x: Int runFuncs({
x = 10 }) { x = 20 } println(x) }
Example 5 @ExperimentalContracts fun runFunc(func: () -> Unit) { contract
{ callsInPlace(func, InvocationKind.EXACTLY_ONCE) } func() }
Example 5 @ExperimentalContracts fun hoge() { var x: Int runFunc({
x = 10 }) // <- 括弧で括る // Variable 'x' must be initialized println(x) }
Example 6 @ExperimentalContracts fun complex(v: Any?, func: () -> Unit):
Boolean { contract { returns(true) implies (v is String) callsInPlace(func, InvocationKind.EXACTLY_ONCE) } func() return v is String }
Example 6 @ExperimentalContracts fun hoge(v: Any) { var x: Int
if (complex(v) { x = 10 }) { println("length = ${v.length}") } println("x = $x") }
注意
注意 class Helper { @ExperimentalContracts fun isNonNull(s: String?): Boolean {
// Contracts are allowed only for top-level functions contract { returns(true) implies (s != null) } return s != null } } •Top-Level関数でしか使えない
まとめ
まとめ •Contractsを使うとComplierがちょっと賢くなる •拡張関数で使うのが現実的な気がする •今後に期待?
ありがとうございました