Bool? 型で ?? を使わないためのテクニック

## はじめに

Swift の入門的な記事です。
次のようなコードから `??`（ Nil-Coalescing Operator ）をなくすためのテクニックについて扱います。

```swift
if a ?? true {
  doSomething()
}
```

## 前置き・動機づけ

多くのプログラミング言語では、条件分岐における `== true` を習慣的に嫌います。

```swift

if a == true {
  print("a is true")
}
```

そして、次のような記述の方が簡潔で好まれています。

```swift
if a {
  print("a is true")
}
```

しかしながら、Optional 型の場合は、このような記述はできません。
Bool? と Bool は異なる型であり、Bool? は条件式として評価ができないからです。

```swift
var a: Bool? = ...
if a { // コンパイルエラー
}
```

そこで、習慣的には嫌われている `== true` が役に立ちます。
二項演算子 `==` は戻り値として Bool 型の値を返すのでコンパイルエラーになりません。

```swift
var a: Bool? = ...
if a == true {
  print("a is true")
}

if a == false {
  print("a is false")
}

if a == nil {
  print("a is none")
}
```

このような場合に、`??`（ Nil-Coalescing Operator ）を使うことでも Bool 型の値を返すことができますが、二項演算子 `==` を用いた方が直感的で可読性が高いと思います。

```swift:どちらも条件分岐の結果は同じ
if a ?? false {
  print("a is true")
}

if a == true {
  print("a is true")
}
```

`??` の方が直感的でない理由は、「`a` 自体が何であるか」に注目しているのではなく、「`a` が `nil` の場合に条件分岐すべきか」に注目しているからです。表現が回りくどいのです。

もう少し具体的な例を取り上げてみます。
String? 型の値の文字数が0または、`nil` の場合に空文字として扱いたい場合は次のようになります。

```swift
let text: String? = ...
if text?.isEmpty ?? true {
  print("empty or nil.")
}
```

仕様を何も知らない状態だと、次のようにコードリーディングすると思います。

1. `text` に文字列が設定されていれば、 `isEmpty` が評価される
    1. `isEmpty` が `true` ならば `print` される
    2. `isEmpty` が `false` ならば `print` されない
1. `text` に文字列が設定されていなければ、`??` の後ろが評価される
    1. `true` なので `print` される
1. つまり、空白文字列または `nil` の場合に `print` される

たった１行で、これだけの判断が必要になります。

こういう記述の仕方に慣れてしまい、プロジェクトのいたるところでこのような記述をしてしまうと、
将来のコードリーディングにおいて、コストになるはずです。

ということで、`??` を使わない表現に置き換えてみましょう。

## `??` を使わないテクニック

引き続き、先程の例を取り上げます。

String? 型の値の文字数が0または `nil` の場合に空文字として扱いたい場合です。
このとき、`??` を使わない表現を考えます。

```swift
let text: String? = ...
if text?.isEmpty ?? true {
  print("empty or nil.")
}
```

この場合は、`text` は文字数が0または、`nil` の場合を考えているので、そのことをそのまま条件式にします。コード量は多くなりますが、そのまま読んでいくことができます。

```swift:??&nbsp;を使わない表現：その１
// text は空白または nil
if text?.isEmpty == true || text == nil {
  print("empty or nil.")
}
```

`||` が短絡的に先頭から評価することを利用して、先に `nil` 判定をしても良いです。そうすれば、`== true` を省略するという習慣にも合わせる事ができます。

```swift:??&nbsp;を使わない表現：その２
// text は nil または空白
if text == nil || text!.isEmpty {
  print("nil or empty.")
}
```

Bool? が `true`, `false`, `nil` の三値しかないことに着目すると、`false` に一致しなければ良いので次のように記述することもできます。コード量は少なくなりますが、否定表現なので先述の表現よりは若干分かりにくかもしれません。

```swift:??&nbsp;を使わない表現：その３
if text?.isEmpty != false { // != で false を否定
    print("empty or nil.")
}
```

最後に、`switch` を使ったパターンマッチです。

```swift:??&nbsp;を使わない表現：その４
switch text?.isEmpty {
case true?, nil:
  // true または nil  
  print("empty or nil.")
case false?:
  break
}
```

次のようなパターンマッチもできますが、若干分かりにくかもしれません。

```swift:??&nbsp;を使わない表現：その５
switch text?.isEmpty {
case false?:
  break
case _:
  // true または nil  
  print("empty or nil.")

}
```

通常は上記のような表現は記述しませんが、複数の変数を扱う場合に便利です。タプルでパターンマッチすれば上述と同じように記述ができます。

```swift:??&nbsp;を使わずに複数の値を判定する
let text1: String? = ...
let text2: String? = ...

switch (text1?.isEmpty, text2?.isEmpty) {
case (false?, _), (_, false?):
    break
case _:
    print("both texts are empty or nil.")
}
```

以上のように Bool? 型で `??` をやめると、`true`, `false`, `nil` の三値との比較やパターンマッチになります。「対象のオブジェクトが何であるか」だけに集中できるので、コードリーディングの際の負担を減らすことができると思います。