Google I/O 2017 : Introduction to Kotlin (和訳/要約)

# Keynote&Developer Keynote

## [Keynote](https://www.youtube.com/watch?v=Y2VF8tmLFHw)

KeynoteにおいてKotlinはAndroid開発における公式言語としてサポートされることが発表されました。
合わせて、

- JetBrains社とパートーナーとしてKotlin財団の設立
- 既存のコード(Java)にもさらなる投資をする

ことが発表されています。

Kotlinが公式言語としてサポートされるに至った背景についてKeynote内では以下のような項目があげられています。

- KotlinはAndroidの開発者コミュニティが既に求めていた言語で、開発者の生産性を高めることが出来る
- Androidのランタイムとの完全な互換性があり、既存のコードとの相互運用が可能である
- 素晴らしいIDEによるサポート
- 言語が成熟し、製品版としてリリース可能な状態である

## [Developer Keynote](https://www.youtube.com/watch?v=EtQ8Le8-zyo)

Developer KeynoteではAndroid/Google Playにおいて大きな4つのテーマについて話がされました。

- Kotlin
- Android Studio & Libraries
- App Quality & Success
- Android Instant App

そのうちの一つとしてKotlinは取り上げられ、Kotlinは「first-class language」としてサポートされ、Android StudioにKotlinが組み込まることになりました。
ただし、Java、C++への投資は引き続き変わらず行われ、追加としてKotlinはサポートされます。

Developer Keynote内で2つのKotlinに関するセッションが発表されました。

- Introduction to Kotlin
- Life is Great and Everything Will Be Ok Kotlin is Here
 - スライド : https://speakerdeck.com/jakewharton/life-is-great-and-everything-will-be-ok-kotlin-is-here-google-io-2017
 - 動画 : https://www.youtube.com/watch?v=fPzxfeDJDzY

# Introduction to Kotlin

## 概要

前半はJetBrains社[Hadi Hariri](https://twitter.com/hhariri)氏によるライブコーディング、後半は同じくJetBrains社のKotlin言語リード開発者である[Andrey Breslav](https://twitter.com/abreslav)氏によるプレゼンテーションでした。  
Keynoteと同じ会場が8割ほど埋まるほど大盛況のセッションとなりました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">Introduction to Kotlin <a href="https://twitter.com/hashtag/IO17?src=hash">#IO17</a> <a href="https://t.co/KhOxsqFDnH">pic.twitter.com/KhOxsqFDnH</a></p>&mdash; Satoru Fujiwara (@satorufujiwara) <a href="https://twitter.com/satorufujiwara/status/865621650628263936">2017年5月19日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

特に前半のライブコーディングはこれからKotlinでAndroid開発を始める人にとっては必見の内容となっています。
セッションの内容はYoutubeで見ることが出来ます。
https://www.youtube.com/watch?v=X1RVYt2QKQE

本記事では特に前半のライブコーディングの部分について和訳・要約をしました。
動画を見る上での参考にしていただければ幸いです。

## ライブコーディング by Hadi Hariri

Kotlinを使って、どう書くか？どういう利点があるかの紹介をします。

まずは[data class](https://kotlinlang.org/docs/reference/data-classes.html)の紹介です。
`amount`と`currency`という2つのread only propertyを持ったdata classを定義します。

```Kotlin
data class Money(val amount: Int, val currency: String)
```
これをJavaで書くと以下のようになります。

```Java
public class JavaMoney {

    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "JavaMoney{" +
                "amount=" + amount +
                "currency='" + currency + '\'' +
                '}';
    }

    public JavaMoney(int amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    private int amount;
    private String currency;


    public int getAmount() {
        return amount;
    }

    public String getCurrency() {
        return currency;
    }

}
```
read only propertyなのでJavaの場合はgetterしかありません。
`toString`、`clone`(Kotlinの場合は`copy`)、`equals`、`hashCode`と4つのメソッドも定義されています。
これらのメソッドはIDEが自動生成してくれたりしますが、メンテンナンス時に変更が必要になったときには変更に関連するコードを全て変更していく必要があります。

次にエントリポイントとなるfunctionを定義します。

```Kotlin
fun main(args: Array<String>) {

}
```
Javaではstaticなメソッドをclass内に定義する必要がありますが、Kotlinはその必要はありません。
JavaScriptのように(もっと良い形で)、トップレベルに定義することが出来ます。
これはfunctionに限らず、propertyやclassもいかなる場所に定義することが出来ます。

```Kotlin
val tickets = Money(100, "$")
```
`tickets`という名のインスタンスを定義します。
Kotlinは型推論があるので、型を明記する必要はありません。

```Kotlin
val popcorn = tickets.copy(500, "EUR")
```
`copy`を使って`popcorn`という新しいインスタンスを定義します。
同じpropertyを持つ場合は`copy`には引数が必要ありませんが、違う値をpropetryに代入したい場合は`copy`の引数に渡すことが出来ます。

```Kotlin
if (tickets != popcorn) {
    println("They are different!")
}
```
`!=`を使ってインスタンスの持つpropertyそれぞれが全て等しいかの比較が出来ます。
同じオブジェクトかどうかの比較は[`!==`を用います](https://kotlinlang.org/docs/reference/equality.html)。

```Kotlin
val javaMoney = JavaMoney(100, "$")
javaMoney.amount
```
KotlinからJavaを呼ぶことが出来ます。
JavaでのgetterはKotlinからはpropertyのように変換されて呼び出すことが出来ます。

```Java
Money money = new Money(100, "$");
money.getAmount();
```
JavaからのKotlinを呼ぶことが出来、KotlinのpropertyはJavaからはgetterのように見えます。
このように相互に呼び出せることによって同じプロジェクトでJavaとKotlinが共存出来ます。

```Kotlin
fun sendPayment(money: Money) {
    println("Sending ${money.amount}")
}
```
`sendPayment`というfunctionをトップレベルに定義します。
Kotlinのfunctionは戻り値が特にない場合は`void`のように定義する必要がなく、デフォルトは`Unit`というシングルトンのクラスが返されます。

```Kotlin
fun sendPayment(money: Money, message: String = "") {
    println("Sending ${money.amount}")
}
```
[functionの引数にはデフォルト値を設定する](https://kotlinlang.org/docs/reference/functions.html#default-arguments)ことが出来ます。
また呼び出し時には[名前をつけて呼び出す](https://kotlinlang.org/docs/reference/functions.html#named-arguments)ことが出来ます。

```Kotlin
sendPayment(message = "Good luck!", money = tickets)
```
どの引数に何を渡してるかがわかりやすくなります。

```Kotlin
fun sum(x: Int, y: Int) = x + y
```
一行でfunctionを定義することが出来、戻り値も暗黙的に定義されるので明記する必要はありません。

```Kotlin
fun convertToDollars(money: Money): Money {
    when (money.currency) {
        "$" -> return money
        "EUR" -> return Money(money.amount * BigDecimal(1.10), "$")
        else -> throw IllegalArgumentException("not the currency you're interested")
    }
}
```
上記のようなfunctionも以下のように一行で書くことが出来ます。

```Kotlin
fun convertToDollars(money: Money) = when (money.currency) {
    "$" -> money
    "EUR" -> Money(money.amount * BigDecimal(1.10), "$")
    else -> throw IllegalArgumentException("not the currency you're interested")
}
```

ここ以降、data classを以下のように変更しています。

```Kotlin
data class Money(val amount: BigDecimal, val currency: String)
```

[拡張関数](https://kotlinlang.org/docs/reference/extensions.html#extension-functions)を用いれば`BigDecimal`のような既存のclassにfunctionを増やすことが出来ます。

```Kotlin
fun BigDecimal.percent(percentage: Int) = this.multiply(BigDecimal(percentage)).divide(BigDecimal(100))
```
以下のように呼び出します。

```Kotlin
val bd1 = BigDecimal(100)
bd1.percent(7)
```

```Kotlin
infix fun Int.percentOf(money: Money) = money.amount.multiply(BigDecimal(this)).divide(BigDecimal(100))
```
`Int`などのクラスも拡張することが出来、[`infix`](https://kotlinlang.org/docs/reference/functions.html#infix-notation)を用いることで、以下のように呼び出すことが出来ます。

```Kotlin
7 percentOf popcorn
```

```Kotlin
private val Int.bd: BigDecimal
    get() = BigDecimal(this)
```
拡張関数と似たような形で[拡張property](https://kotlinlang.org/docs/reference/extensions.html#extension-properties)を用いれば以下のように`long`と似た形で`BigDecimal`のインスタンスをつくることが出来ます。

```Kotlin
val long = 100L
val bd2 = 100.bd
```

Kotlinでは`+`,`-`,`*`などのオペレーターをオーバーライドすることが出来ます。

```Kotlin
operator fun Money.plus(money: Money) =
    if (currency == money.currency) {
        Money(amount + money.amount, currency)
    } else
        throw IllegalArgumentException("We're gonna have a problem here!")
```
`plus`という名前のoperator functionをオーバーライドすれば以下のように呼び出すことが出来ます。

```Kotlin
val costs = tickets + popcorn
```

```Kotlin
val train: Money = Money(100.bd, "$")
train = null // error!
```
新しいインスタンスを定義して`null`を代入しようとするとエラーとなります。
これは正確には2つの意味でエラーとなっています。
`val`はimmutable(不変)を表現していて、一度値を代入しようとすることは出来ません。
以下のように`var`に置き換えることでmutableにすることが出来ます。

```Kotlin
var train: Money = Money(100.bd, "$")
train = null // error!
```
Kotlinにおいてはデフォルトの型がnullableではないので、`var`に置き換えてもエラーが出ます。
`Money?`と`?`をつけることでnullableな型を宣言出来ます。
Kotlinの場合はnullableな型を持ちたくないので、ほとんどこうする必要がないでしょう。
しかし、KotlinはJavaとの互換性があり、Javaの型はnullableです。

```Kotlin
fun javaMoney(money: JavaMoney?) {
    println("${money.amount} is valid") // error!
}
```
nullableな型を引数にとるfunctionを定義して、その引数のpropertyを呼びだそうとするとエラーとなります。
これを解決するには2つの方法があります。
1つ目はnullチェックをすることです。

```Kotlin
fun javaMoney(money: JavaMoney?) {
    if (money != null) {
        println("${money.amount} is valid")
    }
}
```
(動画では述べられてませんがここには後述の[smart cast](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts)が使われています。)

2つ目は[`?`を使ってpropertyを呼び出す](https://kotlinlang.org/docs/reference/null-safety.html#safe-calls)ことです。

```Kotlin
fun javaMoney(money: JavaMoney?) {
    println("${money?.amount} is valid")
}
```
楽しみたいのなら別の方法もあります。

```Kotlin
fun javaMoney(money: JavaMoney?) {
    println("${money!!.amount} is valid")
}
```
[`!!`というオペレーター](https://kotlinlang.org/docs/reference/null-safety.html#the--operator)はnullであることを知りながらも墓穴を掘りたい時に使います。

次は[higher-order function(高階関数)](https://kotlinlang.org/docs/reference/lambdas.html)についての話をします。

```Kotlin
fun findEmails(users: List<User>, predicate: (String) -> (Boolean)): List<User> {
    TODO("LATER!")
}
```
上記のようなfunctionを定義します。
余談ですが`TODO`は呼び出すと`NotImplementedError`を投げる関数として用意されています。

```Kotlin
data class User(val id: Int, val username: String, val email: String, val role: Role)

enum class Role {
    Admin,
    Regular
}

fun usersFromJSONfile(fileName: String): List<User> {
    val gson = Gson()
    return gson.fromJson<List<User>>(FileReader(fileName), object : TypeToken<List<UserResult>>() {}.type)
}
```
以上のようなdata classとfunctionを用意して`findEmails`を呼び出します。

```Kotlin
val users = usersFromJSONfile("users.json")
findEmails(users, { value -> value.endsWith(".com") })
```
lambdaを第二引数にとり、emailが.comで終わるユーザーを見つけることが出来ます。
lambdaの引数が一つの場合、明示的に宣言する必要はなく、`it`を使って引数を呼び出せることが出来ます。

```Kotlin
findEmails(users, { it.endsWith(".com") })
```
さらに、functionの最後の引数がlambdaの場合、`()`の中に入れる必要はありません。

```Kotlin
findEmails(users) {
    it.endsWith(".com")
}
```

以上のようなことは改めて実装する必要はなく、[build-inのfunction](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/index.html)を使って実装することが出来ます。

```Kotlin
val dotComUsers = users.filter { it.email.endsWith(".com") }
            .sortedBy { it.id }
            .map { Pair(it.email, it.username) }
```
email.が.comで終わるユーザを見つけ、idでソートし、emailとusernameのpairにしています。
これらのfunctionはとても小さいライブラリとしてリリースされており、Androidにおいても全く問題なく使うことが出来ます。

Pairは`to`というfunctionを使うことでより良く書けます。

```Kotlin
val dotComUsers = users.filter { it.email.endsWith(".com") }
            .sortedBy { it.id }
            .map { it.email to it.username }
```

data classとして定義されたclassは[destructuring-declaration](https://kotlinlang.org/docs/reference/multi-declarations.html#destructuring-declarations)を使うことが出来ます。

```Kotlin
val (id, username, email) = users.filter { it.email.endsWith(".com") }
            .sortedBy { it.id }
            .first()
println(id)
```
使わない変数は`_`に置き換えましょう。

```Kotlin
val (id, _, _) = ...
```

次に[sealed class](https://kotlinlang.org/docs/reference/sealed-classes.html)について紹介します。
まず、Kotlinのclassはデフォルトでは継承できません。
`open`をつける必要があります。

```Kotlin
class UserResult
data class Success(val users: List<User>) : UserResult() // error!
data class Failure(val message: String) : UserResult() // error!
```

```Kotlin
open class UserResult
```

UserResultをsealed classとして宣言します。

```Kotlin
sealed class UserResult
data class Success(val users: List<User>) : UserResult()
data class Failure(val message: String) : UserResult()
```

sealed classはclassのヒエラルキーを表現したクラスで、UserResultを継承したclassが上記以外にないことを示しています。
(enumの拡張のようなものです。)
継承したclassは同じfileに書く必要があります。

```Kotlin
sealed class UserResult {
    data class Success(val users: List<User>) : UserResult()
    data class Failure(val message: String) : UserResult()
}
```
上記のようにネストして書くことも出来ますが`UserResult.Success`のように書く必要があるので、ここではしません。
(Kotlinの1.1までは上記のようにネストして書く必要があった。)

このclassは成功時と失敗時で違ったpropertyを持つclassを返したい時に使えます。

```Kotlin
fun retrieveUsers(): UserResult {
    return Success(usersFromJSONfile("users.json"))
}
```

```Kotlin
val result = retrieveUsers()
    when (result) {
        is Success -> result.users.forEach { println(it.username) }
        is Failure -> println(result.message)
    }
```
`when`の中の`is Success`以降の`result`は[smart cast](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts)されており、`Success`という型にcastされています。
`is Failure`以降の`result`も同様に`Failure`にcastされています。

ここまではeager evaluation(先行評価)の話でしたが、lazy evaluation(遅延評価)の例を紹介します。

```Kotlin
val values = generateSequence(1) {
    it * 10
}

values.take(10).forEach { println(it) }
```
`generateSequence`で作られるsequenceは無限で終わりがありませんが、`take(10)`で最初から10件だけ取得し、それらを出力しています。

```Kotlin
val users = usersFromJSONfile("users.json").asSequence()
```
`asSequence`を用いることでlazy evaluationへ置換することが出来ます。

## プレゼンテーション by Andrey Breslav

将来、Kotlinがどのようになっていくかの話をします。

1つめの大きな方向はKotlinが様々なプラットフォームをサポートする方向に向かっています。

JVM上、Android、JavaScript(ブラウザ、node.js)でKotlinは動きますが、テクニカルプレビュー版として出している[Kotlin/Native](https://github.com/JetBrains/kotlin-native)はiOS、Linux、MAC、Windowsといったプラットフォーム上のコードにコンパイルされ、動作するように作っています。

1つのウェブアプリケーションがサーバサイドもクライアントもKotlinで書かれて、共通化のコードがそれらの間でシェア出来るようにマルチプラットフォームを目指しています。

2つめは[Coroutines](https://kotlinlang.org/docs/reference/coroutines.html)です。
非同期的なプログラミングから、コールバックや複雑なフローを取り除き、sequentialなコードで書けることを目指しています。

Kotlinを始めたい場合は以下のサイトからはじめてください。

- Official Kotlin Site
[kotlinlang.org](https://kotlinlang.org/) or [kotl.in](http://kotl.in/)

- Kotlin for Android Resource
[kotl.in/android](http://kotl.in/android)