immutableのメリットまとめ

## mmutableとimmutable
`immutable`と`mmutable`は対になっており、それぞれメリットとデメリットがあります。
`immutable`は「不変」、`mmutable`は「可変」の意味を持っています。

「可変」の方が、つまり`mmutable`の方が変更しやすくて良さそうに思いますが、その変更しやすさのゆえバグの温床になります。

## 配列と文字列
一般に配列は操作可能で、文字列は操作不可能です。

ただしここでの操作は、変数の操作（再代入）ではなく、データそのものの操作に関してです。
下記が例です。

プリミティブである`String`に関しては、"my name"の操作ができません。

```kotlin
class User {
    private val name: String = "my name"
    private val friends: MutableList<String> = mutableListOf("matuo", "tanaka", "hamada")
    
    fun updateName() {
        name.append("hoge") // nothing method
    }
    
    fun appendFriend() {
        friends.add("sakata") // ok
    }

}
```
ただしvarを利用することで、再代入が可能になります。

```kotlin
class User {
    private var name: String = "my name"
    
    fun updateName() {
        name = "hoge" // ok
    }
}
```

ちなみにkotlinでは、mmutableとimmutableのlistがそれぞれ存在しています。
collectionはimmutableで、mutableListはmmutableです。

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-collection/

## immutableなクラスとmmutableなクラス、その問題点

次に、mmutableなクラスを考えてみます。

メンバ変数をvarで定義したので、変数が再代入可能という意味でmmutableになっています。

```kotlin
class User(name: String, age: Int) {
    var name: String
    var age: Int
    
    init {
        this.name = name
        this.age = age
    }
      
}
```

### 同一インスタンスのメンバ書き換え

次に下記のコードを実行し、同一インスタンスに対して名前の書き換えを行います。

``` kotlin
    val user = User("hamada", 35)
    println("${user.hashCode()}") // 598446861
    println("${user.name}: ${user.age}") // hamada: 35
    user.name = "tanaka"
    println("${user.hashCode()}") // 598446861
    println("${user.name}: ${user.age}") // tanaka: 35

```

同一ハッシュ（インスタンス）に対して、名前の書き換えが行われています。
これは問題でしょうか。

確かに問題ではあるものの、名前の書き換えを行うことは実際に起き得るので「書き換えが簡単に行われている」ことが確かに問題です。

### 変数の代入によるメンバ書き換え
次に同じ例を用いて下記のコードを実行します。

```kotlin
    val user = User("hamada", 35)
    println("${user.name}: ${user.age}") // hamada: 35

    val user2 = user 
    user2.name = "asada"
    println("${user2.name}: ${user2.age}") // asada: 35
    println("${user.name}: ${user.age}") // asada: 35
```

`val user2 = user `によって参照先が渡され、`user2`の変更が`user`に影響してしまっています。
新しいユーザーを作成したつもりが、`mmutable`であるが故に意図しない変更が起こりうるのです。

## 解決策: immutableなクラスを生成する
今回の本題のimmutableなクラスに関してです。

`kotlin`の`data class`でメンバをval定義します。
これだけでひとまずimmutableなクラス定義は完了です。

```kotlin
data class User(val name: String, val age: Int)
val user = User("hamada", 35)
user.name = "tanaka" // Val cannot be reassigned
```

新しい`tanaka`ユーザーを作成したい場合はインスタンスをさらに作成する必要があります。
```kotlin
data class User(val name: String, val age: Int)
val user1 = User("hamada", 35)
val user2 = User("tanaka", 25)
```

### immutableなクラスの値の更新について

メンバに`val`をつけて、再代入を不可にすることでimmutabilityを獲得しました。
しかし、※1楽観的更新でユーザーの情報を更新したい場合にはどうすれば良いのでしょうか。

`data class`には`copy`メソッドが用意されているのでそちらを利用しましょう。

```kotlin
    var user = User("hamada", 35)
    println("${user.name}: ${user.age}") // hamada: 35
    var newUser = user.copy(name = "tanaka")
    println("${user.name}: ${user.age}") // hamada: 35
    println("${newUser.name}: ${newUser.age}") // tanaka: 35
```

`data class`は他にも`equals`メソッドで等値比較（参照比較ではなく）ができるので、宣言的UIにはとても便利です。

`flutter`では`freezed`パッケージを用いて、簡単に`immutability`を獲得できます。
（コンパイルは伸びます）

※1 楽観的更新
サーバーに通信して、帰ってきた情報からインスタンスを再生成すればimmutableでも更新できますが通信前にimmutableクラスを更新したい場合です。

## まとめ
immutabiltyは大事です。