iOSエンジニアがKotlin触ってみた所感

この記事は[Kotlin Advent Calendar 2015](http://www.adventar.org/calendars/857)の14日目の記事です。
13日目は@Kiriminさんによる[2015年のAndroid開発はKotlinで決まりだったのか？](http://kirimin.hatenablog.com/entry/2015/12/13/000256)でした。

## ご挨拶
初めまして。表題の通り、メインはiOSでたまにAndroidもやるぐらいの人間です。
iOS開発言語としてSwiftの開発環境どんどん整備されてきている昨今、Javaで書くということ自体が足かせとなってAndroidの勉強が放置気味になっていました。
Kotlinは正直ネタ枠だと思っていたのですが、方々の勉強会でもKotlin関連のお話をよく聞くようになり、[Android開発を受注したからKotlinをガッツリ使ってみたら最高だった](http://qiita.com/omochimetaru/items/98e015b0b694dd97f323)を拝見したこと、年内にも正式リリースがされるらしいということで、ならばと門を叩いてみたので、その際に感じたことをつらつらと書いていきます。半分ポエムです。

## 制作物
よくある感じにAPIを叩いて、ローカルに保存、ListViewに表示するようなものを作りました。また、

- [Moshi](https://github.com/square/moshi/)
- [RxJava](https://github.com/ReactiveX/RxJava)/[RxAndroid](https://github.com/ReactiveX/RxAndroid)
- [Realm](https://realm.io/jp/)
- [Retrofit](http://square.github.io/retrofit/)
- [Anko](https://github.com/Kotlin/anko)

あたりを使用し、なんとなく今風な構成とFull Kotlinを目指してみました。
自社のPrivateなAPIを叩いて制作してしまったため、制作物そのままをアップすることはできないのですが、ご要望があれば適当なAPIを叩くものに差し替えて、GitHubにあげます。

**追記** 
アップしました。GitHubのレポジトリの検索 -> 保存 -> 表示というよくある感じです。
https://github.com/WU3110/KitHub

## if/when and Smart Casts
今回Kotlinを勉強していて、最初にSwiftに欲しいなと思ったのはこいつです。
Kotlinの`if`や`when`が他の言語の`if`や`switch`と異なるのは、式であるという点です。つまり、値を返せます。Swiftの`switch`もだいぶ強力になりましたが、それ以上にスマートに記述できます。
例えば、TwitterライクにTweetの作成日時に応じて、〇〇秒前、〇〇分前…と作成日時が表示されるような実装を考えたときに下のように書けます。変数を定義したりメソッドを定義しなくていいので読みやすいですね。

```kotlin
val diff = // 現在日時と作成日時の差(秒)
textView.text = when(diff) { 
	in 0..60 -> "$diff 秒前"
	in 60..60*60 -> "${diff/60} 分前"
	in 60*60..60*60*24 -> "${diff/(60*60)} 時間前"
	else -> {
		// 適当に整形
	}
}
```

また、KotlinにはSmart Castsという機能があり、簡単に言えば`if`や`when`で型チェックを通した後は、そのままその型にキャストされた状態で使えるものです。

```kotlin
fun smartCastDemo(x: Any?) {
	if (x != null && x is String) {
		print(x.length) // automatically cast to String
	}
}
```

`when`と組み合わさると高い表現力を持てそうなことをわかっていただけるかと思います。
Smart Castsに関しては、Swiftでも同様にUnwrap Optionalできますね！

```swift
func unwrapOptionalDemo(x: Any?) {
	if let x = x as? String {
		print(x.characters.count)
	}
	
	// もしくは
	guard let x = x as? String else { return }
	print(x.characters.count)
}
```

## スコープ関数
Kotlinのstdlibには`let`, `with`, `run`, `apply`の4つのスコープ関数があります。これも素敵です。
4つ関数はどれもよく似ていて使い分けが難しいのですが、この点は[Kotlin スコープ関数 用途まとめ](http://qiita.com/ngsw_taro/items/d29e3080d9fc8a38691e)で、わかりやすく解説されています。
私は`apply`をよく利用します。オブジェクトを初期化した後に書くプロパティに値をセットしていくというのはよくある処理だと思いますが、この時の処理を下のように書くことができます。毎度、`article.~`と書く必要がなく簡潔ですね。さらに、StringをDateにパースするためにSimpleDateFormat型で`dateFormat`を宣言していますが、こいつが名前空間を汚しません。素敵です。

```kotlin
// 普通に書くと
val article = Article()
article.title = "今日のおすすめ晩御飯レシピ"
article.url = "https://~"
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
article.createDate = dateFormat.parse(createDateString)

// apply関数
val article = Article().apply {
	title = "今日のおすすめ晩御飯レシピ"
	url = "https://~"
	val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
	createDate = dateFormat.parse(createDateString)
}

```

蛇足ですが、Objective-C時代には処理ブロックの明確化と名前空間汚染対策としてこんなコードをよく書いていました。あまり見る書き方ではなかったですが。

```objc
Article *article = ({
	Article *a = Article();
	// 色々と処理
	return a;
});

```

## interface/protocol
SwiftではProtocol Oriented Programmingというものが提唱されており、詳細は[「Swift 2で提唱されているProtocol Oriented ProgrammingをWWDCセッションから学ぶ」](http://qiita.com/mono0926/items/bb52e657df6978713334)が詳しいのでそちらをご覧いただくとして、ともかく、振る舞いの表現を継承によって実現することはあまりありません。Kotlinの流儀としてどういうものが推奨されているのかは知らないですが、抽象クラスを作るくらいならinterfaceを作る、必要ならばinterfaceにデフォルト実装を持たせるといったSwift風のスタイルはKotlinでも同様に実装できました。こういった点でも普段、Swiftを書くのと同じノリで実装ができます。

## 辛かったこと
言語仕様という意味で辛い部分というのはほとんどありませんでした。
辛かったのもJavaで書かれた既存のライブラリとの相性が悪い時くらいのものでしたが、IcePickやDagger等の個人的に依存しているライブラリがそのまま使えなかったのはなかなか手間でした。

JSONのデコードに利用した **Moshi** にも地味な辛さがありました。
MoshiはSquare社による軽量なJSONパーサです。JacksonやGsonに比べメソッド数が相当に抑えられており、Androidでは嬉しい存在です。また、単純にJSONをPOJOに変換するだけならば十分な機能を備えているかと思います。（KotlinでもPOJOって言うんですかね？）

こんな感じで定義してみました。

```kotlin
data class UserData (
        val id: Int,
        val name: String,
        val gender: Int,
        val introduction: String?,
        @Json(name = "created_at") val craeteDate: DateTime, 
        val children: List<ChildData>
)
```

Data Classはデータを保持するだけのクラスは幾つかのメソッドは機械的に生成できるという経験から生まれたクラスのようです。
具体的には`equals()`,`hashCode()`, `toString()`等ですが、`toString()`をよしなに生成してくれるので、デバッグが楽になりました。

Primitive以外のクラスに対するConverterの作成も含め、Kotlinでも基本的な使用に問題はなかったですが、JSONにKeyが存在しなかった場合はプロパティの型を **非Optionalで宣言していても** nullが入ってきました…
`val location: String = ""`のようにデフォルト値を設定しておきましょう。
せっかくのKotlinでぬるぽは辛い。

### JSON Decoding in Swift
余談ですが、私がSwiftでJSONをデコードするときは[Himotoki](https://github.com/ikesyo/Himotoki)を用いています。
上記と同じことをこんな感じでかけます。おすすめです。SwiftyJSONはもうやめにしませんか？

```swift
struct UserData: Decodable {
    
    let id: Int
    let name: String
    let geder: Int
    let introducation: String?
    let craeteDate: NSDate
    let children: [ChildData]
    
    static func decode(e: Extractor) throws -> UserData {
        return try ArticleData(
            id: e <| "id",
            name: e <| "name",
            gender: e <| "gender",
            introduction: e <|? "introduction",
            createDate: NSDate.fromString(e <| "created_at"), // NSDate Extension
            children: e <|| "children"
        )
    }
}
```

## まとめ
Kotlinの開発元であるJetBrain社は
> 100% interoperable with Java™

を謳っていますが、時折そのまま書き換えるだけというわけにもいかないものもあります。
この辺りの知見もコミュニティの人数が多いに作用するところだと思います。
まだベータ版ということもあり、「まだ早い」という印象をお持ちの方も多いでしょうが、だからこそ、今、世のSwiftエンジニアの皆さん、冬休みにでもtry Kotlinしてみませんか。

日本KotlinコミュニティのSlackグループでの、日本Kotlin界の先鋒の方々のトークは眺めているだけでも勉強になります。

- [http://kotlinlang-jp.herokuapp.com](http://kotlinlang-jp.herokuapp.com)

勉強会も頻繁に開かれています！

- [https://connpass.com/search/?q=kotlin&start_from=2016%2F12%2F12&start_to=](https://connpass.com/search/?q=kotlin&start_from=2016%2F12%2F12&start_to=)

本も出てます。

- [Kotlinスタートブック -新しいAndroidプログラミング](http://taro.hatenablog.jp/entry/2016/06/16/203136)  
日本Kotlinユーザーグループ代表の@ngsw_taroさんによるKotlin本！最初の一冊として間違いない一冊。
- [Kotlin for Android Developers](https://leanpub.com/kotlin-for-android-developers) (英語)