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
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.4k
Jetpack Compose の Side-effect を使いこなす / DroidKaigi 2023
star_zero
5
6.4k
Android 14 新機能 / Android 14 Meetup Nagoya
star_zero
1
620
Android 14 と Predictive back gesture / Shibuya.apk #42
star_zero
0
420
Coroutines Test 入門 / Android Test Night #8
star_zero
2
1.2k
What's new in Jetpack / I/O Extended Japan 2022
star_zero
1
660
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
Web Components で実現する Hotwire とフロントエンドフレームワークの橋渡し / Bridging with Web Components
da1chi
3
2.5k
Leading Effective Engineering Teams in the AI Era
addyosmani
5
420
私達はmodernize packageに夢を見るか feat. go/analysis, go/ast / Go Conference 2025
kaorumuta
2
560
オープンソースソフトウェアへの解像度🔬
utam0k
15
2.8k
チームの境界をブチ抜いていけ
tokai235
0
170
Go Conference 2025: Goで体感するMultipath TCP ― Go 1.24 時代の MPTCP Listener を理解する
takehaya
9
1.7k
高度なUI/UXこそHotwireで作ろう Kaigi on Rails 2025
naofumi
4
4.1k
コードとあなたと私の距離 / The Distance Between Code, You, and I
hiro_y
0
170
株式会社 Sun terras カンパニーデック
sunterras
0
310
Six and a half ridiculous things to do with Quarkus
hollycummins
0
170
そのpreloadは必要?見過ごされたpreloadが技術的負債として爆発した日
mugitti9
2
3.4k
iOSエンジニア向けの英語学習アプリを作る!
yukawashouhei
0
190
Featured
See All Featured
Leading Effective Engineering Teams in the AI Era
addyosmani
5
420
Navigating Team Friction
lara
190
15k
Why Our Code Smells
bkeepers
PRO
340
57k
Speed Design
sergeychernyshev
32
1.2k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
30
2.9k
The World Runs on Bad Software
bkeepers
PRO
72
11k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
9.7k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Designing Experiences People Love
moore
142
24k
The Power of CSS Pseudo Elements
geoffreycrofte
79
6k
Building Applications with DynamoDB
mza
96
6.7k
Writing Fast Ruby
sferik
629
62k
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がちょっと賢くなる •拡張関数で使うのが現実的な気がする •今後に期待?
ありがとうございました