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
570
ContractsでCompilerを賢くしよう / love_kotlin #5
star_zero
October 24, 2018
Tweet
Share
More Decks by star_zero
See All by star_zero
Jetpack Compose の Side-effect を使いこなす / DroidKaigi 2023
star_zero
4
4k
Android 14 新機能 / Android 14 Meetup Nagoya
star_zero
1
490
Android 14 と Predictive back gesture / Shibuya.apk #42
star_zero
0
300
Coroutines Test 入門 / Android Test Night #8
star_zero
2
740
What's new in Jetpack / I/O Extended Japan 2022
star_zero
1
570
Kotlin 2021 Recap / DevFest 2021
star_zero
3
1.2k
Kotlin Symbol Processing (KSP) を使ったコード生成 / DroidKaigi 2021
star_zero
2
5k
What's new Android 12
star_zero
0
520
これからはじめるAndroid開発 / DevFest 2020
star_zero
4
670
Other Decks in Programming
See All in Programming
Fragment Composition of GraphQL
quramy
13
1.4k
デフォルトにして至高、RubyMineの大好きな所
ruzia
0
700
2 週間で Twitter Bot を作ってみた
contour_gara
0
760
禅の心を手に入れよ
eltociear
1
280
Exploring the Implementation of “t.Run”, “t.Parallel”, and “t.Cleanup”
akarin
1
110
効率化に挑戦してみたらモバイル開発が少し快適になった話
ryunakayama
0
140
Go製Webアプリケーションのエラーとの向き合い方大全、あるいはやっぱりスタックトレース欲しいやん / Kyoto.go #50
utgwkk
6
1.7k
Milestoner
bkuhlmann
1
410
Build Apps for iOS, Android & Desktop in 100% Kotlin With Compose Multiplatform (mDevCamp 2024)
zsmb
0
420
Amazon SQSコンシューマー疎結合への旅 - 出張! #DevelopersIO IT技術ブログの中の人が語る勉強会 #3
quiver
0
300
Next.js App Router
quramy
11
1.6k
Elm 0.19.0 Changes
bkuhlmann
0
500
Featured
See All Featured
The Mythical Team-Month
searls
216
42k
Fontdeck: Realign not Redesign
paulrobertlloyd
76
4.9k
Build your cross-platform service in a week with App Engine
jlugia
226
17k
VelocityConf: Rendering Performance Case Studies
addyosmani
321
23k
KATA
mclloyd
16
12k
Put a Button on it: Removing Barriers to Going Fast.
kastner
58
3.1k
Fireside Chat
paigeccino
22
2.6k
What's in a price? How to price your products and services
michaelherold
238
11k
Unsuck your backbone
ammeep
663
57k
Building Your Own Lightsaber
phodgson
100
5.7k
Teambox: Starting and Learning
jrom
128
8.4k
Mobile First: as difficult as doing things right
swwweet
217
8.6k
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がちょっと賢くなる •拡張関数で使うのが現実的な気がする •今後に期待?
ありがとうございました