Kotlin 1.3 まとめ（Coroutines、Kotlin/Native以外の変更点）

# はじめに

Kotlin 1.3が 2018/10/30 にリリースされました
ここでは以下に記載の変更点をメインでまとめていきます（全部は網羅していません）

- [What's New in Kotlin 1.3][wahts_new]

実際のサンプルコードがあるところの再生ボタンを押すとそのコードが実行されて結果が参照できます
便利なので試してみてください！

## 注意点

基本的には上記の公式リファレンスを和訳しつつ、各種参考サイトを利用させていただきながらまとめています
英語力があまり自信ないので、内容に不備等があるかもしれませんがご容赦ください
むしろご指摘いただけるとうれしいです！

また、注目のCoroutinesやKotlin/Nativeに関してはまとめていません。
それだけでかなりのボリュームになりますので、別の投稿などでまとめていければと思ってはいます。
（予定は決まってないですが。。。）

## Kotlinのmigration tool

今回は機能が多いためか、Migration Toolが提供されています

`Tools > Kotlin > Enable migrations detection (experimental)`


# 主な機能

公式ブログで一通り紹介されています

- [公式ブログ - 日本語][jetbrains_blog_jp]

やはり、注目はCoroutines、Kotlin/Nativeでしょうか
今回はこの中の「その他の改善」に入っているような内容を詳しく書きたいと思います

# 変更点

Kotlin 1.3から変わる点についてまとめます

## Coroutines

正式にリリースされたことでパッケージ名が変更されたようです

- 変更前

```kotlin
import kotlinx.coroutines.experimental.*
```

- Kotlin 1.3

```kotlin
import kotlinx.coroutines.*
```

## Contracts

便利な機能としてスマートキャストがあります

```kotlin
fun foo(s: String?) {
    if (s != null) s.length // Compiler automatically casts 's' to 'String'
}
```

ただし、チェックが別の関数などに分離されるとスマートキャストされません

```kotlin
fun String?.isNotNull(): Boolean = this != null

fun foo(s: String?) {
    if (s.isNotNull()) s.length // No smartcast
}
```

こういった課題を解決するために`Contracts`という機能が追加されました
`Contracts`は以下の２ケースでサポートされています

- 関数の戻り値と引数の関係を宣言することで、スマートキャストを改善する

    ```kotlin
    fun require(condition: Boolean) {
        // これはコンパイラに以下のような指示をするための構文です:
        // 「この関数が正常に成功するときは、引数のconditioinはtrueです」
        contract { returns() implies condition }
        if (!condition) throw IllegalArgumentException(...)
    }

    fun foo(s: String?) {
        require(s is String)
        // ここで「s」はStringにスマートキャストされます
        // できないときはrequireから例外がスローされます
    }
    ```

- 高階関数が存在する場合の変数の初期化解析の改善

    ```kotlin
    fun synchronize(lock: Any?, block: () -> Unit) {
        // 「この関数はblockを一度だけ呼び出します」とコンパイラに指示します
        contract { callsInPlace(block, EXACTLY_ONCE) }
    }

    fun foo() {
        val x: Int
        synchronize(lock) {
            x = 42  // コンパイラは、synchronizeに渡されたラムダが1回だけ呼び出されることを知っているので、
                    // 再割り当ては報告されません
        }
        println(x)  // コンパイラはラムダが確実に呼び出され、初期化されることを知っているので
                    // 「x」は初期化されるとみなされます
    }
    ```

### Contracts in stdlib

`stdlib`はすでに`Contracts`が導入されているので、追加のオプトインをすることなくすぐに恩恵が受けられます
Kotlin1.3からは以下のメソッドに`Contracts`が追加されています

- `run`, `with`, `apply`, `also`, `let`, `takeIf`, `takeUnless`, `synchronized`
    - ラムダの引数が１度呼び出される
- `repeat`
    - ラムダの引数が何回か呼び出される
- `assertTrue`, `require`, `check`
    - 引数がtrueである
- `assertFalse`
    - 引数がfalseである
- `isNullOrEmpty`, `isNullOrBlank`, `assertNotNull`, `checkNotNull`, `requireNotNull`
    - 引数はnullではない


### Custom Contracts

カスタムで`Contracts`宣言をする機能は`experimental`で提供されています
現時点での構文は early prototype なので変更される可能性があります

## when

`when`でローカル変数を定義できます
`when`で利用するローカル変数のスコープがより正確になります

```kotlin
fun Request.getBody() =
        when (val response = executeRequest()) {
            is Success -> response.body
            is HttpError -> throw HttpException(response.status)
        }
```

## `@JvmStatic`, `@JvmField`

`interface`の`companion object`メンバーに`@JvmField`, `@JvmStatic`アノテーションを付与できるようになりました
ただし、`interface`にstatic変数、メソッドを持てるのがJava1.8からなので、もし使う場合はJVM targetを1.8にする必要があります

## Nested declarations in annotation classes

`annotation class`に`enum`と`companion object`をネスト出来るようになりました
具体的には以下のようなコードです

```kotlin
annotation class Foo {
    enum class Direction { UP, DOWN, LEFT, RIGHT }
    
    annotation class Bar

    companion object {
        fun foo(): Int = 42
        val bar: Int = 42
    }
}
```

## Parameterless main

Androidはあまり関係ありませんが、`main`関数の引数が不要になりました

```kotlin
fun main() {
    println("Hello, world!")
}
```

## Functions with big arity

今までは関数の引数は、最大22個という制限がありましたが、Kotlin1.3からはより多くの引数がとれるようになりました
特に個数が明記されてないですが、普通に作る上で不都合はないのではないかと思います

## Progressive mode

プログレッシブモードを有効にすると、コードの安全性と正確性が向上するコンパイラでコンパイルできるようになります
重要な特性としては以下の２つがあります

- プログレッシブモードが有効な状態でコンパイルできるコードは無効にしてもコンパイルできることを保証している
- 基本的にはよりコードを安全にするだけである
    - 例：一部の不正なスマートキャストを禁止する、生成されたコードの動作をより安定に変更する

# experimental

Kotlin1.3からexperimentalに導入されている機能を紹介します

## Inline classes

`inline class`はプロパティや関数の宣言ができますが、以下のような制約があります

- プライマリコンストラクタで初期化される単一のプロパティのみ宣言できる
- `init`ブロックは持てない
- 内部クラスは持てない
- バッキングフィールドを持てない
    - 単純な計算可能なプロパティ（`lateinit `/ `delegated`プロパティなし）のみを持つことができます
- インターフェースを実装することはできるが、クラス階層に参加することはできない

```kotlin
inline class Name(val s: String) {
    val length: Int
        get() = s.length

    fun greet() {
        println("Hello, $s")
    }
}    

fun main() {
    val name = Name("Kotlin")
    name.greet() // greet()はstatic関数として呼ばれます
    println(name.length) // static関数としてgetterが呼ばれます
}
```

メインの用途としては、ビジネスロジックの層でプリミティブな型ラップする時に使うようなイメージでしょうか。

## Unsigned integers

符号なし整数型が導入されています

- `kotlin.UByte`：符号なし8ビット整数。範囲は0〜255
- `kotlin.UShort`：符号なし16ビット整数、範囲は0〜65535
- `kotlin.UInt`：符号なし32ビット整数、範囲は0〜2 ^ 32 - 1
- `kotlin.ULong`：符号なし64ビット整数、範囲は0〜2 ^ 64 - 1

## `@JvmDefault`

Java1.8の`interface`にdefault関数が定義できるようになっています

# Standard library

## Multiplatform Random

利用できる全てのプラットフォームで乱数の生成方法が統一されました

```kotlin
import kotlin.random.Random

fun main() {
    val number = Random.nextInt(42)  // number is in range [0, limit)
    println(number)
}
```

## isNullOrEmpty/orEmpty extensions

`CharSequence`などにはすでに導入されていますが、`Collection`, `Map`, `Array`にも導入されました

## Copying elements between two existing arrays

`array.copyInto(targetArray, targetOffset, startIndex, endIndex)`で要素のコピーができます

```kotlin
val sourceArr = arrayOf("k", "o", "t", "l", "i", "n")
val targetArr = sourceArr.copyInto(arrayOfNulls<String>(6), 3, startIndex = 3, endIndex = 6)
println(targetArr.contentToString())

sourceArr.copyInto(targetArr, startIndex = 0, endIndex = 3)
println(targetArr.contentToString())
```

## associateWith

`key`のリストから値を関連づけてマップを作成する際に利用します

```kotlin
val keys = 'a'..'f'
val map = keys.associateWith { it.toString().repeat(5).capitalize() }
map.forEach { println(it) }
```

## ifEmpty and ifBlank functions

`Collections`, `maps`, 配列などに`ifEmpty`, `ifBlank`が追加されました
空の場合に代わりに使用できる値が指定できます

```kotlin
fun printAllUppercase(data: List<String>) {
    val result = data
    .filter { it.all { c -> c.isUpperCase() } }
        .ifEmpty { listOf("<no uppercase>") }
    result.forEach { println(it) }
}

printAllUppercase(listOf("foo", "Bar"))
printAllUppercase(listOf("FOO", "BAR"))
```

## Sealed classes in reflection

KotlinのReflectionに`sealed class`のサブクラスを列挙することができるAPIが追加されました


# まとめ

コードが正確かつ安全に書ける機能が多く追加されている印象ですね。
個人的にはスマートキャスト周りの改善や`when`で変数持てるのが特にうれしいです。
ますますKotlinでの開発がしやすくなっていきそうです。

# 参考

- [公式ブログ][jetbrains_blog]
- [公式ブログ - 日本語][jetbrains_blog_jp]
- [AABrain - Kotlin1.3の新機能][aabrain_blog]


[wahts_new]:https://kotlinlang.org/docs/reference/whatsnew13.html
[jetbrains_blog]:https://blog.jetbrains.com/kotlin/2018/10/kotlin-1-3/
[jetbrains_blog_jp]:https://blog.jetbrains.com/jp/2018/10/30/1511
[aabrain_blog]:https://aakira.app/blog/2018/10/whatsnew-kotlin13/
[migration_guide]:https://kotlinlang.org/docs/reference/code-style-migration-guide.html