3分で作る Kotlin Friendly な API

Preview:

Citation preview

3分で作る Kotlin FriendlyなAPI

@kikuchy

だれ?

• Hiroshi Kikuchi (@kikuchy)

• Diverse, inc. (mixi, inc.)

• Androidアプリ作ってます

34301 Lines 432 Files

79.4 Lines/File

6970 Lines 125 Files

55.8 Lines/File

Kotlinは 短く書けて 読みやすい

本題

対象

• Kotlinは使い始めくらいの人

• Androidアプリ作れるくらいにはJavaが使える人

• Javaでライブラリ作ってる(作りたい)人

Javaのライブラリ作ってて困ったこと

例:Keninhttps://github.com/kikuchy/kenin

// 入力必須で、英字のみもしくは数字のみ可 KeninAndroid.create( mUserId, CompositeCondition.and( Conditions.requireField("require!!!! must put some value!!"), CompositeCondition.or( Conditions.alphabet(), Conditions.numeric() ) ) );

きもい

// 入力必須で、英字のみもしくは数字のみ可 KeninAndroid.create( mUserId, CompositeCondition.and( Conditions.requireField("require!!!! must put some value!!"), CompositeCondition.or( Conditions.alphabet(), Conditions.numeric() ) ) );

作用されるインスタンスが引数から入る

強制逆ポーランド記法

クラス名長い。かと言ってstatic importしまくるのも避けたい…

目的

• 「作用されるもの」をレシーバにしたい!

• Builderパターン(や、それに類するもの)をもっと直感的に、読みやすくしたい!

材料• 拡張関数

• 引数末尾がラムダ式であればメッセージ式の丸括弧を省略できること

• ラムダ式のreturnは省略できること

• thisは省略できること

• レシーバ指定関数

• 中置換数

• (演算子オーバーロード)

完成予想図

// 入力必須で、英字のみもしくは数字のみ可 userId.kenin { requireField() and (alphabet() or numeric()) }

読める、読めるぞ!

拡張関数• TextInputLayoutに新しいメソッド(に見えるstatic

メソッド)を生やします

// トップレベルで宣言すればいい // thisでレシーバー(この場合はTextInputLayout型のインスタンス)を参照可能 fun TextInputLayout.kenin(…) = KeninAndroid.create(this, …)

丸括弧の省略• 最後の引数がラムダ式のとき、メッセージ式の () を

省略できる

• ブロックのような表記が可能

// 今回は Condition 型が欲しいので、戻り値で受け取るようにする fun TextInputLayout.kenin(init: () -> Condition) = KeninAndroid.create(this, init())

// この時点で、この表記が可能に! userId.kenin { // ラムダ式末尾のreturnは省略できる CompositeCondition.and( Conditions.requireField(), CompositeCondition.or( Conditions.alphabet(), Conditions.numeric() ) ) }

thisの省略• staticメソッドのためにクラス名を書きたくない

• ブロック内のthisを差し替えてnon-staticなメソッド呼び出しにしてしまえばいい

// このクラスのインスタンスがthisになってくれればいい class Delegated { fun requireField() = Conditions.requireField() fun alphabet() = Conditions.alphabet() fun numeric() = Conditions.numeric() }

レシーバ指定関数• 関数のレシーバを型宣言で指定できる

• 拡張関数とよく似たようなもの

// このクラスのインスタンスがthisになってくれればいい fun TextInputLayout.kenin(init: Delegated.() -> Condition) = KeninAndroid.create(this, Delegated().init())

// 完成は近い! userId.kenin { CompositeCondition.and( requireField(…), CompositeCondition.or( alphabet(), numeric() ) ) }

中置関数• 拡張関数の一種として中置関数を作ることができる

• 引数は必ず1つである必要がある(二項演算でなければならない)

• 特定の名前のメソッドを宣言することで演算子のオーバーロードもできるので、それで代用する手もある

// 同じようにして or のバージョンも作る infix fun Condition.and(another: Condition) = CompositeCondition.and(this, another)

// 完成!! ✧\\ ٩۹( 'ω' )وو //✧ userId.kenin { requireField() and (alphabet() or numeric()) }

DSLのバリエーション

相性がいいものは?

• 設定項目が多くて

• 構造化が必要かもしれなくて

• Javaで書くとつらいもの

Anko• https://github.com/Kotlin/anko

• DSLでAndroidのUIをつくるためのライブラリ

• たろうさんのスライドがあるのでそちらをご参照ください

• Ankoは甘くて美味しい~Ankoに見るKotlinの表現力~ #gunosybeer

• http://sssslide.com/speakerdeck.com/ntaro/ankohagan-kutemei-wei-sii-ankonijian-rukotlinfalsebiao-xian-li-number-gunosybeer

kotlinx.html• https://github.com/Kotlin/kotlinx.html

• KotlinでDOMツリーを作ることができる

• サーバーサイドでのテンプレート作成はもちろん

• KotlinはJavaScriptにもトランスパイルできる、ということは…!

Kotlin NoSQL

• https://github.com/cheptsov/kotlin-nosql

• MongoDBのクエリもDSLで構築可能

• (Mongoは使ったこと無いので詳しいことはわかりません)

ここが惜しいよKotlin

&& と || のオーバーロードはできない?

• 四則演算子やほとんどの比較演算子はオーバーロードできるのだけれど…

• Kotlinのリファレンスを見ても、&&と||は記載がない

• https://kotlinlang.org/docs/reference/operator-overloading.html

• andとかorとか書いてもダメだった

• Booleanクラスにはandとorメソッドがある

• 諦めも肝心

まとめ

• Kotlinの言語機能を駆使すれば可読性が高いDSLも作れる

• JavaライブラリのKotlinラッパーを用意するとKotlinist達にも親切

こちらもよろしく

Keninreal-time validation framework for Java & Kotlin

https://github.com/kikuchy/kenin

@kikuchy