Swiftのextensionは3パターンだけ〜そして条件付き適合へ･･･〜


Xcode 9.3 正式版が一向にリリースされないため、しびれを切らして投稿します。
**(追記)** -> 翌日にリリース来ました。念願のSwift 4.1や。**Swift 4.1の次はSwift 4.2で、その次はSwift 5.0や!**

## 本記事の効能

- Swiftの`extension`は3つの用法しかないことを知り、それぞれのパターンをはっきり峻別できるようになる
- また、それぞれのパターンに付与された`where`の意味も完全に把握し、Swift 4.1でお試し解禁された`条件付き適合(conditional conformance)`まで知識をビルドアップする
- 結果、さらに自信を持って`extension`を扱えるようになり、Swiftがさらに楽しくなる

Swift 4.1以上をご用意のうえ、お読みいただけると嬉しいです。

## 環境
Xcode 9.3
Swift 4.1

## 全3パターンを把握する

どんなに複雑そうに見える`extension`定義でも、用法別に見れば、わずか3パターンしかありません。

```
用法1: クラス・構造体・列挙体に定義を追加する
用法2: プロトコル拡張(protocol extension)
用法3: クラス・構造体・列挙体をプロトコルに適合させる
```

たったこれだけです。

ひとたび実際のコードの世界に飛び込むと、当たり前のように`where`節が絡んだ複雑な`extension`定義に遭遇しますが、恐るるに足らず。
よくよく見るとその用法はたった3つしかないことを知るだけで、勇敢に立ち向かう気概が湧いてきます。
それぞれのパターンの見分け方も押さえながら、みっちりと理解していきましょう。
(なお今回は、`where`節以下に書ける記法の仔細には立ち入らないこと、ご承知おきください。
自分自身の理解のため、後日改めてまとめたいと欲望しております。)

### 用法1: クラス・構造体・列挙体に定義を追加する

最も素朴な使い方です。
**既存のクラス・構造体・列挙体に対し、新たな定義を追加**します。

以下の例は、標準ライブラリの構造体`Int`に、インスタンスメソッド`times`を新たに定義しています。

```swift
extension Int {
    // 自身の回数だけ、引数に渡されたクロージャを実行するメソッド
    func times(repeat: (Int) -> Void) {
        // `repeat` は予約語なので、``でエスケープする
        (0..<self).forEach { n in `repeat`(n) }
    }
}

3.times{ _ in print("Hello!") }

// 結果
Hello!
Hello!
Hello!
```

こちらは、標準ライブラリの構造体`Bool`に、コンピューテッドプロパティ`number`を新たに定義しています。

```swift
extension Bool {
    // 自身の値に応じた整数を返す
    var number: Int { return self ? 1 : 0 }
}

print(true.number)   // 1
print(false.number)  // 0
```

#### 構文(見分け方)

```swift
// []: 任意で付加される場合がある、という意味です
extension クラス名|列挙体名|構造体名 [where ...] {
  ...
}
```

`extension`の直後に型名(クラス・列挙体・構造体)が来ればこのパターンです。

#### 追加できる定義

詳解Swift 第3版 P244によると、`extension`で新たに追加できる定義は、以下の通りです。

- 格納型(stored)のタイププロパティ、計算型(computed)のインスタンスプロパティ、計算型(computed)のタイププロパティ
- インスタンスメソッド、タイプメソッド
- イニシャライザ
- サブスクリプト
- ネスト型定義

逆に追加できないのは、以下の通りです。

- 格納型(stored)のインスタンスプロパティ
- プロパティオブザーバ


#### `where`が付加された場合

話が前後してしまい恐縮ですが、
そもそもまず、用法1~3に共通する、`extension`に付加される`where`の基本的な意味について。

`where`以下には、特定の制約を付加していくことができます(型制約)。
それにより、**制約を全て満たした場合のみ有効**となる定義を記述することができます。[^1]

```swift
extension ○○ where 制約1, 制約2... {
  制約をすべて満たす場合にのみ有効となる定義
}
```

[^1]: Swift実践入門(初版)の説明を参考にさせていただきました。

話を戻して...今回の用法1に対して`where`が付加された場合、
**型が`where`以下の条件を満たす場合のみ有効になる定義を追加する**という構文になります。

以下の例は、Arrayの型パラメータ`<Element>`が`Int`で特殊化された場合のみ有効になるインスタンスメソッド`sum`を追加しています。

```swift
// 「[Int]の場合のみ有効になる定義を、これから定義します」
extension Array where Element == Int {
    // 配列の各要素の総和を返す
    func sum() -> Int {
        return reduce(0, +)
    }
}

print([1,2,3,4,5].sum())    // 15
print([true, false].sum())  // コンパイルエラー。∵ [Bool]では、インスタンスメソッド `sum`は有効にならない
```

### 用法2: プロトコル拡張(protocol extension)

続いてのパターンです。
プロトコルに対し`extension`を用いることで、**プロトコルのデフォルト実装を定義**することができます。
プロトコルに適合する型定義の中にその実装がなくても、
あたかも最初から実装していたかのようにプロパティにアクセスしたり、メソッドを呼び出したりできます。

```swift
// パーティメンバーが備えているべき各種ステータスが宣言されたプロトコル
protocol Party {
    var name: String { get }
    var lv:   Int    { get }
    var HP:   Int    { get }
}

extension Party {
    // プロトコル`Party`が使用できるデフォルト実装
    var info: String {
        // 本体のプロトコル定義で宣言したプロパティが使用できる点に注目♪
        return "名前: \(name), レベル: \(lv), HP: \(HP)"
    }
}

struct Devil: Party {
    let name: String
    var lv:   Int
    var HP:   Int
}

let jack_O_Frost = Devil(name: "ジャックフロスト", lv: 7, HP: 78)
print(jack_O_Frost.info)  // `Devil`の定義には`info`は宣言されていないのに、何食わぬ顔で`info`を使用できる!

// 結果
名前: ジャックフロスト, レベル: 7, HP: 78
```

#### 構文(見分け方)

```swift
// []: 任意で付加される場合がある、という意味です
extension プロトコル名 [where ...] {
  ...
}
```

`extension`の直後にプロトコル名が来ればこのパターンです。
用法1との差異は「プロトコル名か? それとも型名(クラス・列挙体・構造体)か?」だけなので、
名前から判断しかねる場合、定義ジャンプでプロトコルか否か確認するとよいかもしれません。

#### 追加できる定義

プロトコル拡張で新たに追加できる定義は、以下の通りです。

- 計算型(computed)のインスタンスプロパティ、計算型(computed)のタイププロパティ
- インスタンスメソッド、タイプメソッド
- サブスクリプト

反対に、できないものは、以下の通りです。

- イニシャライザ
- ネスト型定義

#### `where`が付加された場合

プロトコル拡張に対して`where`が付加された場合、
**プロトコルに適合する型が`where`以下の条件を満たす場合のみ有効になるデフォルト実装を追加する**という構文になります。

以下の例は、プロトコル`Swimmable`と`Runnable`の両方に適合している型でのみ有効になるインスタンスメソッド`swagger`を追加しています。
(`extension`定義に出てくる`Self`は当記事で初めて出現した表現ですが、"実際にこのプロトコルに適合した具体的な型" のことを指します。)

```swift
protocol Swimmable {
    func swim()
}

protocol Runnable {
    func run()
}

// 「`Swimmable`に適合した型が`Runnable`にも適合している場合にのみ有効になる定義を書きます」
extension Swimmable where Self: Runnable {
    // いばって歩く
    func swagger() {
        print("陸でも水でも無敵だぞ😤")
    }
}

// ワニさんは水陸両用
struct Alligator: Swimmable, Runnable {
    func swim() {
        print("ぶくぶく")
    }
    func run() {
        print("シュタタタ")
    }
}

// イルカさんは水中専用
struct Dolphin: Swimmable {
    func swim() {
        print("すいすい")
    }
}

let alligator = Alligator()
alligator.swagger()

// 結果
陸でも水でも無敵だぞ😤 (∵ ワニさんは`Swimmable`かつ`Runnable`なので、`swagger`を呼べる)

let dolphin = Dolphin()
dolphin.swagger()

// 結果
コンパイルエラー: (∵ イルカさんは`Swimmable`しか適合していないので、`swagger`を呼べない)
```

### 用法3: クラス・構造体・列挙体をプロトコルに適合させる

最後のパターンです。
`extension`を使うことで、**クラス・構造体・列挙体をプロトコルに適合させ**ることができます。

iOS開発で頻出するこちらの典型例を引き合いに出すのがよいでしょう。
`UIViewController`を継承した独自型を、UIKitのプロトコル`UITableViewDataSource`に適合させたい場合、
実直に書くとこのようになると思いますが...。

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController, UITableViewDataSource {

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
        cell.label.text = "ヒーホー!"
        return cell
    }
    
}
```

これを以下のように書き換えることができます。

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
}

// extensionを用いることでも、型をプロトコルに適合できる♪
extension ViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
        cell.label.text = "ヒーホー!"
        return cell
    }
    
}
```

プロトコルへの準拠宣言(`: UITableViewDataSource`の部分)と、そのプロトコルが要求する実装を、`ViewController`の定義の外にくくり出しただけですね...?
ですがこれにより、各プロトコルが要求する実装が型定義本体から切り分けられ、ひいては可読性が向上するとされています。
また、くくり出した`extension`の定義は、別ファイルに記述することも可能です。

#### 構文(見分け方)

```swift
// []: 任意で付加される場合がある、という意味です
extension クラス名|列挙体名|構造体名 : プロトコル名 [where ...] {
  ...
}
```

用法1と用法2に**`:`**は出現しないので、この記号があれば用法3だと即判断できますね。

#### `where`が付加された場合

これまで見てきたパターンと、`where`が付加されたときの意味は、それぞれ以下のものでした。

|パターン|意味|`where`が付加された場合|
|:-:|:-:|:-:|
|extension ○○(クラス名/列挙体名/構造体名)|型に定義を追加する|条件を満たした場合のみ使用できる定義を追加
|extension ○○(プロトコル名)|プロトコル拡張|条件を満たした場合のみ使用できるデフォルト実装を追加
|extension ○○(クラス名/列挙体名/構造体名): ××(プロトコル名)|型をプロトコルに適合させる|?????

それでは、この用法3に`where`が付加された場合は...?
?????

## 『第三のwhere』解禁: 【条件付き適合】発現

これまで出てきた2つの用法に`where`が付加された場合は、
いずれの場合も「**特定の条件を満たした場合のみ、○○する**」という意味になったのでした。

それを鑑みると、用法3の場合も、`where`が付加された場合の意味の推測が立ちます。
**「特定の条件を満たした場合のみ、型をプロトコルに適合させる」**

...まさにその通り。
これが、Swift 4.1で~~実験的機能として~~追加された、**「条件付き適合(conditional conformance)」**という機能にあたります。
([Proposal](https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md)には「Status: **Implemented (Swift 4.2)**」とあるように、
~~正式な機能として認められるのは~~完全な機能を有するのはSwift 4.2から、ということのようです。)
**(追記)** -> いただいたコメントを受け、表現を少し変更しました。コメント欄も参照ください。


|パターン|意味|`where`が付加された場合|
|:-:|:-:|:-:|
|extension ○○(クラス名/列挙体名/構造体名)|型に定義を追加する|条件を満たした場合のみ使用できる定義を追加
|extension ○○(プロトコル名)|プロトコル拡張|条件を満たした場合のみ使用できるデフォルト実装を追加
|extension ○○(クラス名/列挙体名/構造体名): ××(プロトコル名)|型をプロトコルに適合させる|**条件付き適合(特定の条件を満たした場合のみ、型をプロトコルに適合させる)** ←new!

### 使用例

(**この項目は、特に`Swift 4.1以降`の説明の仕方であることにご留意いただけると幸いです**)

条件付き適合の説明にあたり、 例えば[こちら](https://qiita.com/Kuniwak/items/681d5d2c20e149e2a0ef)に見られるような**「`[Equatable]`は`Equatable`でない問題」**が引き合いに出されることが多いと思います(リンク先、型の理解を深める上でも非常に学びになりました)。
なので、今回は自分なりの例を作っての説明にトライしてみます。

Swiftの標準ライブラリにキュー(Queue)が用意されていないことに気づいた私が、
独自のデータ構造`Queue`を作りたくなったとします。
今回は、[こちら](https://qiita.com/shoheiyokoyama/items/31eca0d4b27bc9608eb8)の記事を拝借させていただきながら、キューが空のときに`dequeue`すると例外を投げる実装にしてみました。

```swift
struct Queue<Element> {
    
    enum QueueError: Error {
        case queueIsEmpty
    }
    
    private var elements = [Element]()
    
    mutating func enqueue(_ newElement: Element) {
        elements.append(newElement)
    }
    mutating func dequeue() throws -> Element {
        guard !elements.isEmpty else { throw QueueError.queueIsEmpty }
        return elements.remove(at: 0)
    }
}
```

このように使用することができます。

```swift
var queue1 = Queue<Int>()
queue1.enqueue(1)  // [1]
queue1.enqueue(2)  // [1,2]

try! queue1.dequeue()   // 1 elements => [2]
try! queue1.dequeue()   // 2 elements => []
```

そんな折、ふとこんなことを思いつきます:
『どうせなら2つのQueueが同じと見なせるかどうか、判定できるようにしたい』

こんなことができたらいいな、って思ったんですよね。

```swift
var queue1 = Queue<Int>()
queue1.enqueue(1)  // [1]
queue1.enqueue(2)  // [1,2]

var queue2 = Queue<Int>()
queue2.enqueue(1)  // [1]
queue2.enqueue(2)  // [1,2]

print(queue1 == queue2)  // true ←こう書けるようにしたい
```

ただし、現時点ではこのコードはコンパイルエラーになってしまいます。
`Queue`が`Equatable`に適合していないのだから当然か。

```swift
print(queue1 == queue2)

// 結果: コンパイルエラー
Binary operator '==' cannot be applied to two 'Queue<Int>' operands
```

というわけで、`Queue`を`Equatable`に適合させましょう。せっかくなので`extension`を使って。
2つの`Queue`が同じだとみなされる条件は...
「`Queue`が内部に持つ要素とその順序がすべて同じならば同じ」、これでいきましょう。

```swift
// 用法3: `Queue`を`Equatable`に適合させる
extension Queue: Equatable {
    static func ==(lhs: Queue<Element>, rhs: Queue<Element>) -> Bool {
        // `Queue`が内部に持つ要素とその順序がすべて同じなら、同じとみなす
        return lhs.elements == rhs.elements
    }
}
```

ですが、このコードもコンパイルエラーになってしまいます。
(以下のコードはSwift 4.1で試していますが、4.0.3だと別のエラーメッセージが出るのでご注意ください)

![Screen Shot 2018-03-27 at 11.14.16 PM.png](https://qiita-image-store.s3.amazonaws.com/0/105411/e778ba86-926a-872c-50e4-37db5058f712.png)

赤色のエラーメッセージ部分に着目すると、
「`Elements`に対し`==`を呼び出すには、`Queue`の型パラメータ`<Element>`が`Equatable`に適合している必要があるよ」、
「`<Element>`が`Equatable`に適合してないよ」、と言われています。

さらに褐色のエラーメッセージ部分に着目すると(画像の左側にあるペインの、背景が青色になっている部分をクリックすると表示される)、
「`Element`が`Equatable`に適合している必要があるよ」、
「"`条件付き適合`" "`[Element]`を`Equatable`に"」という、いかにもなキーワードが並んでいます。

これらはどういうことなのでしょうか?

今見ているように、`Element`型の配列どうしが同じかどうか確かめるコード `lhs.elements == rhs.elements`は、コンパイルエラーになってしまいます。
ただし奇妙なことに、こちらのコードは正常に実行でき、期待通りの結果が返ります。

```swift:この配列同士はエラーにならず、ちゃんと比較できている...!?
print([1,2,3] == [1,2,3])  // true
```

なぜ、配列によって `==` を呼び出せる場合とそうでない場合があるのでしょうか?

実は、条件付き適合は既にSwiftの標準ライブラリの中にも取り入れられており、その影響は`Array`にも及んでいました。
今回のケースに関連する部分を見てみます(関連する部分だけを抽出しています)。

```swift:Array.swift(4.1)
extension Array : Equatable where Element : Equatable {
  public static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool {
    ...
  }
}
```

この記法はまさに条件付き適合で、**「Arrayの型パラメータ`<Element>`が`Equatable`とみなせる場合に限り、Arrayも`Equatable`に適合する」**(その結果として、`==`も呼べるようになる)という定義となります。

これで、配列によって`==`が実行できる場合とそうでない場合がある理由が判明しました。
`[1,2,3] == [1,2,3]`の場合は、配列の要素(`Int`)が`Equatable`に適合しているため、配列自体も`Equatable`に適合し、結果として`==`を呼び出すことができました。
一方elementsの場合、elementsの要素(`Element`)が`Equatable`に適合しているという定義は、現時点ではどこにも書いていません。
そのため、elementsは`Equatable`に適合しておらず、当然`==`(`lhs.elements == rhs.elements`の部分)も呼び出すことができなかった(コンパイルエラーになった)、というわけですね。

```swift
// elementsが `Equatable` だなんて、これまでどこにも書いてない...
struct Queue<Element> {
    ...

    private var elements = [Element]()

    mutating func enqueue(_ newElement: Element) { ... }
    mutating func dequeue() throws -> Element    { ... }
}

extension Queue: Equatable {
    static func ==(lhs: Queue<Element>, rhs: Queue<Element>) -> Bool {
        return lhs.elements == rhs.elements  // ← ここでコンパイルエラー
    }
}
```

さて、なんとかここまで来れたのであれば、この定義を完成させるのはもう一息です。

「elementsの要素(`Element`)が`Equatable`に適合していないから配列自体も`Equatable`に適合せず、その結果`==`(lhs.elements == rhs.elements)を実行できない」
そういうのであれば、逆に
**「もし`Element`が`Equatable`だった場合に限っては配列自体も`Equatable`に適合し、その結果`==`** (lhs.elements == rhs.elements) **が実行できる」**
このような書き方ができたら非常に好都合ですよね。
<br>
...でも、**そんな定義の書き方を、既に我々は知っている**のではないでしょうか...?
<br>
やりましょう! Swiftが4.1以降(しつこくてごめんなさい)なことを確認して、いざ。

```swift:条件付き適合
// 前述の`Queue`のextension定義の1行目に、"where Element: Equatable" を追加しただけ
extension Queue: Equatable where Element: Equatable {
    static func ==(lhs: Queue<Element>, rhs: Queue<Element>) -> Bool {
        return lhs.elements == rhs.elements
    }
}
```

コメントにもありますが、この`extension`定義の変更点は、1行目に `where Element: Equatable` を追加しただけです。条件付き適合の書き方になりましたね。
この`where`句の追加により発生したことを追うのは複雑なのですが、一歩ずつ見ていきましょう。

まず、この条件(`where Element: Equatable`)を追加したことによって、
この`extension`定義内(`{ ... }`)は、`Element`型の要素が`Equatable`であることが前提の世界になります
(つまり、`Element`型の要素が`Equatable`であることを前提にコードを書けるようになります)。

するとその結果、elementsが`Equatable`に適合します。
(↑の説明で登場した、Arrayの条件付き適合の定義(条件)を思い出してください。
『配列の要素`(Element)`が`Equatable`なら、配列自体も`Equatable`に適合する』を満たすことになります)
従って、elementsは`Equatable`に適合したことで、`==`が呼べるようになりました。

コンパイルエラーなく定義の内部を完成させることができたので、晴れて`Queue`に対する条件付き適合の定義全体も完成しました。
つまり、`Queue`の条件付き適合の定義は、**その内部で`elements`の条件付き適合が成立していることを前提にして書かれている**わけですね。

完成した条件付き適合が有効かどうか、確認してみましょう。

```swift
var queue1 = Queue<Int>()
queue1.enqueue(1)  // [1]
queue1.enqueue(2)  // [1,2]

var queue2 = Queue<Int>()
queue2.enqueue(1)  // [1]
queue2.enqueue(2)  // [1,2]

print(queue1 == queue2)

// 結果
true

queue1.enqueue(3)  // [1,2,3]

print(queue1 == queue2)

// 結果
false
```

ようやく上手くいきました!

「`Queue`の型パラメータ`Element`が`Equatable`だとみなせる場合のみ、`Queue`は`Equatable`に適合する」ということは当然、
「`Queue`の型パラメータ`Element`が`Equatable`だとみなせない場合は、`Queue`は`Equatable`に適合しない」ですよね。

```swift
// `Equatable`でない型を用意する
struct Devil {
    let name: String
    var lv:   Int
    var HP:   Int
}

var notEqQueue1  = Queue<Devil>()    // `<Element>`を、`Equatable`でない型(`Devil`)で特殊化
let jack_O_Frost = Devil(name: "ジャックフロスト", lv: 7, HP: 78)
notEqQueue1.enqueue(jack_O_Frost)

var notEqQueue2    = Queue<Devil>()  // `<Element>`を、`Equatable`でない型(`Devil`)で特殊化
let jack_O_Lantern = Devil(name: "ジャックランタン", lv: 19, HP: 162)
notEqQueue2.enqueue(jack_O_Lantern)

print(notEqQueue1 == notEqQueue2)  // ← エラー ∵ 2つの`Queue`は`Equatable`に適合していないので、`==`を呼べない

// 結果: コンパイルエラー
Type 'Devil' does not conform to protocol 'Equatable'
'<Self where Self : Equatable> (Self.Type) -> (Self, Self) -> Bool' requires that 'Devil' conform to 'Equatable'
```

こちらもちゃんとコンパイルエラーになってくれました。

###【追記・余談】 型の性質の表現 ー 関数 vs プロトコル

(この項目は、[参照記事](https://engineering.linecorp.com/ja/blog/detail/227)に、

> Swiftはメソッドやプロパティで性質を判断するというより、プロトコルで一段階抽象化して性質を表現します

という記述があり、この点についてもっと詳しく理解したいと思い、調査・追記しました。)

ところで、条件付き適合がなかったSwift 4.1未満でも、
このように書けば`Queue`に対し`==`を定義し、呼び出すことができました。
こちらのコード、普通にSwift 4.1未満でも有効です。

```swift:私のこれまでの例が適切でなかったことをしれっと白状していくスタイル
// 用法1: 型に対して直接、条件付きで定義を追加
extension Queue where Element: Equatable {
    static func ==(lhs: Queue<Element>, rhs: Queue<Element>) -> Bool {
        return lhs.elements == rhs.elements
    }
}

// この方法でも、`Queue`に対して問題なく`==`を呼び出せる
print(queue1 == queue2) // true
```

`extension`の用法1を用い、`Queue`という型に直接`==`を定義してあげることで、
条件付き適合を用いて行ったこと相当のことを実現できています。

同じことができるのであれば、これまで見てきた小難しいことを考えなくても済むこちらのやり方の方が優れているようにも思えてきます。
この、2つの`==`を呼べるようにする方法に、何か違いはあるのでしょうか?

#### 用法1(定義の追加)では、関数で型の性質を表現

用法1を用いた方法は、
「`Queue`はプロトコル`Equatable`に適合はしていない。
でも、メソッド`==`を持っているおかげで、`Equatable`に相当する振る舞いがたまたま出来ている。」という状態です。
これは、`==`が呼べるという`Queue`の型の性質を、**関数(メソッド)で表現**している状態である、といえます。

こちらの場合、`Queue`はあたかも`Equatable`であるかのように振る舞えますが、
実際には`Equatable`に適合しているわけではありません。

引用先の*"メソッドやプロパティで性質を判断"*という一文は、
RubyやGoなどといった、ダックタイピングな特性を備えた言語を意識した上での表現なのかな、と考察しました。
『`Queue`はメソッド`==`を呼べる(持っている)ので、`Equatable`として振る舞える』というのは、いかにもダックタイピングな挙動なのではないでしょうか。

#### 用法3(条件付き適合)では、プロトコルで型の性質を表現

一方、用法3を用いた方法は、
`Queue`は言うまでもなくプロトコル`Equatable`に(条件付きで)「適合」しています。
これは、`==`が呼べるという`Queue`の型の性質を、(`Equatable`という)**プロトコルで表現**している状態である、といえます。

前者と比較すると、**よりSwiftらしい型の表現**という意味では、こちらの方に軍配が上がるのでしょう。
とはいえ、同じことを実現するために、複数の表現方法があるのは興味深いです。

<!--

これ、indexOf()の実装のお陰で、不都合があったため、掲載せず

また、条件付き適合の方法を採用する小さなメリットとして、
プロトコルに適合した型をコレクション的に扱いたい場合、
`Collection#index(of:)`など、いくつかの便利なメソッドが使えるようになるという恩恵にあずかれます。

```swift
// 予想と違う!!なぜか? index(of)の定義見るとわかる。 == の判定でおかしくなってる。
var queue1 = Queue<Int>()
queue1.enqueue(1)  // [1]
queue1.enqueue(2)  // [1,2]

var queue2 = Queue<Int>()
queue2.enqueue(1)  // [1]
queue2.enqueue(2)  // [1,2]

print([queue1, queue2].index(of: queue2))  // Optional(0)　バグ！！！！
```

これは、例えば`index(of:)`の場合、
コレクションの要素が`Equatable`のときだけ有効になる[デフォルト実装が用意されている](https://github.com/apple/swift/blob/swift-4.1-branch/stdlib/public/core/CollectionAlgorithms.swift.gyb#L37)からですね。(必要な部分だけを抜粋しています。)

```swift:CollectionAlgorithms.swift.gyb
extension Collection where Element : Equatable {
  public func index(of element: Element) -> Index? {
    ...
  }
}
```

まぁ、今回は私の例が最悪で`Queue`それ自体がもはやコレクションなので、実用性はまるで皆無ですが...。

-->

#### Arrayの`==`はグローバル関数だった

さらに余談です。
Swift 4.1になった今でこそ、上述のように型に属する形で定義されるようになった`Array`の`==`ですが、
一つ前のマイナーバージョンである4.0の時点でさえそうではなく、
まさかの**[グローバル関数](https://github.com/apple/swift/blob/swift-4.0-branch/stdlib/public/core/Arrays.swift.gyb#L2169)として定義**されていたのですね。まるで気づきませんでした...。
タイプメソッドとして`Queue`に属していた`==`の例と異なり、こちらはもはや`Array`に引数でしか紐付いてないですが、こちらも一種の**関数による**型の性質の表現、といえるでしょう。

```swift:Array.swift(4.0)
// ウソみたいだろ グローバル関数だったんだぜ
public func ==<Element : Equatable>(lhs: Array<Element>, rhs: Array<Element>) -> Bool {
  ...
}
```

個人的な感覚でも、Swift 4.1以降の定義の方が、自然で気持ち良いと感じます。

## 総仕上げ(実際のソースコードから)

最後に総仕上げとして、`extension`が実際のソースコードでどのように用いられているかを簡単にチェックしていき、知識の定着を試みます。
以下、`extension`はどのような用法で用いられているでしょうか...?

### 例1

[ReactiveX/RxSwift](https://github.com/ReactiveX/RxSwift/blob/master/RxCocoa/iOS/UILabel%2BRx.swift#L14)からの例です。

```swift:UILabel+Rx.swift
...

// 筆者補足: `Reactive`は構造体です
extension Reactive where Base: UILabel {
    
    /// Bindable sink for `text` property.
    public var text: Binder<String?> {
        return Binder(self.base) { label, text in
            label.text = text
        }
    }
    
    ...
}
```
回答例)
 (構造体)`Reactive`に対し、`Reactive`の型パラメータ`<Base>`が`UILabel`とみなせる場合のみ有効になるコンピューテッドプロパティ`text`を定義している。(用法1＋where)

### 例2

[Nirma/Default](https://github.com/Nirma/Default/blob/master/Sources/DefaultStorable.swift#L35)からの例です。

```swift:DefaultStorable.swift
...

// 筆者補足: `DefaultStorable`はプロトコルです
// 筆者補足: `Self` = "実際にこのプロトコルに適合した具体的な型" のことを指します
extension DefaultStorable where Self: Codable {
  ...
  public static func read(forKey key: String? = nil) -> Self? {
        let key: String = key ?? defaultIdentifier
        return defaults.df.fetch(forKey: key, type: Self.self) ?? defaultValue
  }
  ...
}
```

回答例)
 (プロトコル)`DefaultStorable`に対し、このプロトコルに適合した型が`Codable`とみなせる場合のみ有効になるデフォルト実装`read`を定義している。(用法2＋where)

### 例3

[vapor/vapor](https://github.com/vapor/vapor/blob/master/Sources/Vapor/Content/Content.swift#L191)からの例です。

```swift:Content.swift
...

// 筆者補足: `Key == String` = `Key`が`String`だった場合を指します
extension Dictionary: Content, RequestDecodable, RequestEncodable, ResponseDecodable, ResponseEncodable where Key == String, Value: Content {
    /// See `Content.defaultMediaType`
    public static var defaultMediaType: MediaType {
        return .json
    }
}
```

回答例)
`Dictionary`の型パラメータ`<Key>`が`String`と等しく、かつ型パラメータ`<Value>`が`Content`とみなせる場合のみ、
`Dictionary`はプロトコル`Content`と`RequestDecodable`と`RequestEncodable`と`ResponseDecodable`と`ResponseEncodable`に適合する。(用法3＋where)

<!--
[標準ライブラリに定義された`Dictionary`](https://github.com/apple/swift/blob/master/stdlib/public/core/Dictionary.swift#L1376)です。

```swift:Dictionary.swift
...

// 補足: `Dictionary`は構造体です
extension Dictionary: Equatable where Value: Equatable {
  @_inlineable // FIXME(sil-serialize-all)
  public static func == (lhs: [Key: Value], rhs: [Key: Value]) -> Bool {
    ...
  }
  ...
}

...
```

回答例)
`Dictionary`の型パラメータ`<Value>`が`Equatable`とみなせる場合のみ、`Dictionary`は`Equatable`に適合する。(用法3)
-->


## おわりに

私が`extension`に出くわすたび、その用法につきいつも混乱していたため、それを払拭すべく書き始めた今回の記事ですが、実際のソースコードを地道に整理していくことで、その実はとてもシンプルだったことが理解できました。
条件付き適合という新機能によって、`extension`の3用法テーブルの最後のピースが埋まり、美しい対応関係がSwiftの文法にもたらされた、と個人的に感じています。
Swiftにおけるジェネリクスプログラミングは同言語の中心的なトピックであり、その進化が続いていくことは確実なので、今後も遅れを取らぬよう理解を深めていきたいです。

## links

[Swift 4.1+](https://engineering.linecorp.com/ja/blog/detail/227) (記事を書くに当たり何度も参照させていただきました。Swift 4.1は条件付き適合以外にも目を引く進化があり、それらを総ざらいできる必読の記事だと思います)