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
620
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.2k
Jetpack Compose の Side-effect を使いこなす / DroidKaigi 2023
star_zero
5
5.8k
Android 14 新機能 / Android 14 Meetup Nagoya
star_zero
1
580
Android 14 と Predictive back gesture / Shibuya.apk #42
star_zero
0
370
Coroutines Test 入門 / Android Test Night #8
star_zero
2
1.1k
What's new in Jetpack / I/O Extended Japan 2022
star_zero
1
620
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
560
Other Decks in Programming
See All in Programming
バッチを作らなきゃとなったときに考えること
irof
2
550
Swift Testingのモチベを上げたい
stoticdev
2
150
SwiftUI移行のためのインプレッショントラッキング基盤の構築
kokihirokawa
0
160
Datadog Workflow Automation で圧倒的価値提供
showwin
1
290
Rubyで始める関数型ドメインモデリング
shogo_tksk
0
140
オレを救った Cline を紹介する
codehex
1
140
楽しく向き合う例外対応
okutsu
0
710
ML.NETで始める機械学習
ymd65536
0
240
.NET Frameworkでも汎用ホストが使いたい!
tomokusaba
0
200
PHPカンファレンス名古屋2025 タスク分解の試行錯誤〜レビュー負荷を下げるために〜
soichi
1
740
CDK開発におけるコーディング規約の運用
yamanashi_ren01
2
260
データベースのオペレーターであるCloudNativePGがStatefulSetを使わない理由に迫る
nnaka2992
0
250
Featured
See All Featured
BBQ
matthewcrist
87
9.5k
Optimizing for Happiness
mojombo
377
70k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
40
2k
Thoughts on Productivity
jonyablonski
69
4.5k
Fashionably flexible responsive web design (full day workshop)
malarkey
406
66k
The Invisible Side of Design
smashingmag
299
50k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
7
650
Stop Working from a Prison Cell
hatefulcrawdad
268
20k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
227
22k
Practical Orchestrator
shlominoach
186
10k
Building Flexible Design Systems
yeseniaperezcruz
328
38k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
160
15k
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がちょっと賢くなる •拡張関数で使うのが現実的な気がする •今後に期待?
ありがとうございました