なぜSwiftのプロトコルはジェネリクスをサポートしないのか

Swift のプロトコルは、 Java や C# などのインタフェースのようなものと説明されることが多いですが、いくつかの違いがあります。最も大きな違いの一つが、 Swift のプロトコルはジェネリクスをサポートしていないということです。

`Sequence` プロトコルを例にして説明します。 Swift では、 `Sequence` プロトコルに適合した型は `for` 文で要素を取り出すことができます。

```swift
// Array は Sequence に適合
let array: Array<Int> = [2, 3, 5]
for element in array {
    print(element)
}
```

`struct Array<Element>` はジェネリクスによって型パラメータを持ちますが、 `Sequence` は `protocol Sequence<Element>` のように宣言されているわけではありません。 `Sequence` は次のように宣言されています。

```swift
protocol Sequence {
    associatedtype Element
    associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
    func makeIterator() -> Iterator
 }
```

**`associatedtype` はジェネリクスの型パラメータのようなものに見えるかもしれませんが、 Swift は何のためにわざわざジェネリクスとは別の仕組みを採用しているのでしょうか？**

Java や C# のインタフェースはジェネリクスをサポートしています。 Java では、 Swift の `Sequence` プロトコルに相当するのは `Iterable` インタフェースです。

```java
// Java
interface Iterable<T> {
    Iterator<T> iterator();
}
```

見ての通り Java の `Iterable` はジェネリクスを使って宣言されています。 **ジェネリクスという一つの仕組みで同じことができるならその方がシンプルです。 Swift がわざわざ `associatedtype` を導入したのには何か理由があるはずです。**

`associatedtype` はジェネリクスに似たことを実現しますが、 Swift を使い始めた人がすぐに気づく決定的な違いがあります。それは、 `associatedtype` を持つプロトコル型の変数を作れないことです。

たとえば、 Java では次のようなコードは一般的です。 `Iterable` インタフェース型の変数 `strings` に、新しく生成した `ArrayList` のインスタンスを代入しています。

```java
// Java
Iterable<String> strings = new ArrayList<String>();
```

しかし、同様のコードは Swift （ 4.1 時点）では書けません。

```swift
// Swift
let strings: Sequence<String> = Array<String>() // これはできない⛔️
```

Java に慣れ親しんでいた僕は、 Swift を使い始めた当初、これに相当とまどいました。なにせ、インタフェース型の変数や引数を使うのは、 Java では息をするように当たり前のことです。一体それなしにどのように抽象化をしろというのでしょう？

ややこしいことに、 Swift でもプロトコル型変数を作れる場合があります。 `associatedtype` （と `Self` を含む API ）を持たないプロトコル型の変数は作ることができます。

```swift
protocol Animal {}
struct Cat: Animal {}

let animal: Animal = Cat() // これは OK ✅
```

そのため、僕が初めて Swift を触ったときは、 `associatedtype` を持つプロトコル型変数を作ることができないのは、単に Swift が未成熟で言語機能が足りてないだけかとも思いました（当初の Swift はそう疑われても仕方ない品質でした）。

しかし、 Swift を使う内に、プロトコルがジェネリクスをサポートしないのは Swift によくフィットしていると感じるようになりました。ただ、何度かそのことを説明したいと思ったのですが、なかなかうまく言語化することができませんでした。

1 年半ほど前に @Kuniwak さんの ["Swift の型システムが微妙な件"](https://qiita.com/Kuniwak/items/681d5d2c20e149e2a0ef) という投稿にコメントしたときも、あまり自分の言いたいことを明確に言えずもやもやしていました。そして、ちょっと前に @amarillons さんに、どうして Swift のプロトコルにはジェネリクスがないのかと質問をされて答える中で、自分の考えていることを大分言語化できてきました。それを整理してまとめたのがこの投稿です。

本当はプロトコルがジェネリクスをサポートしない理由を明言したドキュメントがあれば良かったんですが、僕が探した限りそのようなものは見つまりませんでした。一番関連が深そうな[こちらのドキュメント](https://github.com/apple/swift/blob/master/docs/Generics.rst)にもざっと目を通してみましたが、ぴたりとその理由について言及されている箇所はなさそうでした。

ですので、本投稿で述べる内容は「なぜSwiftのプロトコルはジェネリクスをサポートしないのか」を、状況証拠を元に僕が推察したことです。

## プロトコルを型として使うのは最小限にしたい

先程見たように、 Swift では `associatedtype` を持たないプロトコル型の変数を作ることができます。

```swift
protocol Animal {}
struct Cat: Animal {}

let animal: Animal = Cat() // OK ✅
```

しかし、僕はプロトコル型の変数や引数、戻り値を使うことは最小限に留めるべきであると考えています。まずはその理由を説明します。

**Swift は値型を中心とした言語です。 Swift の標準ライブラリでも、 `KeyPath` などの一部の例外を除き、提供されている型のほぼすべてが値型です。** たとえば、ここに列挙した型は全部値型です。

```swift
struct Int { ... }
struct Double { ... }
struct Bool { ... }
struct String { ... }
struct Array<Element> { ... }
struct Dictionary<Key, Value> { ... }
enum Optional<Wrapped> { ... }
```

では、値型の値をプロトコル型変数に代入するときには何が起こっているのでしょうか？

値型の変数は、その値型のサイズ分だけスタック領域にメモリを確保します。 `UInt8` なら 1 バイトの、 `Int32` であれば 4 バイトの領域が確保されます。一方で、参照型の場合はインスタンスの実体はヒープ領域に確保され、変数にはその領域へのアドレスが格納されます。アドレスのサイズは環境に依存しますが、 2018 年現在用いられている Swift の環境ではほぼ 8 バイトと考えて問題ないでしょう。

アドレスのサイズは型によらず一定なので、参照型を抽象的に扱うのは簡単です。

```swift
class Animal {}
class Cat: Animal {}
class Dog: Animal {}

let cat: Cat = Cat() // 変数 cat は 8 バイト
let dog: Dog = Dog() // 変数 dog は 8 バイト

var animal: Animal // 変数 animal は 8 バイト
animal = cat // cat に格納された 8 バイトのアドレスを animal の 8 バイトの領域にコピー
animal = dog // dog に格納された 8 バイトのアドレスを animal の 8 バイトの領域にコピー
```

これと似たようなことを値型でやろうとすると、変数 `animal` のサイズはどうなるのでしょうか？ `animal` に `Cat` や `Dog` のインスタンスを代入すると何が起こるのでしょうか？

```swift
protocol Animal {}
struct Cat: Animal { var foo: UInt8 = 2 }
struct Dog: Animal { var bar: Int32 = 3 }

let cat: Cat = Cat() // 変数 cat は 1 バイト
let dog: Dog = Dog() // 変数 dog は 4 バイト

var animal: Animal // 変数 animal は何バイト？🤔
animal = cat // 何が起こる？
animal = dog // 何が起こる？
```

Swift では、[プロトコル型変数に値を代入すると内部的には existential container という入れ物が作られ、そこに格納されます](https://github.com/apple/swift/blob/master/docs/ABI/TypeLayout.rst#existential-container-layout)。 existential container のサイズは、その種類や環境によって異なりますが、一般的な環境では先の `animal` のサイズは 40 バイトになります。

```swift
print(MemoryLayout<Animal>.size) // 40
```

また、値型の変数経由でメソッドを呼び出すと、実際にどのメソッドが呼び出されるかをコンパイル時に静的に解決できますが、

```swift
struct Cat: Animal {
    func foo() -> Int { return 2 }
}

let cat = Cat()

// コンパイル時に Cat の foo が呼ばれると確定
print(cat.foo()) // 2
```

プロトコル型変数経由でメソッドを呼び出そうとすると existential container の中の witness table を引いて実行時に動的に解決しなければいけません。

```swift
protocol Animal {
    func foo() -> Int
}
struct Cat: Animal {
    func foo() -> Int { return 2 }
}
struct Dog: Animal {
    func foo() -> Int { return 3 }
}

var animal: Animal = Bool.random() ? Cat() : Dog()

// Cat と Dog のどちらの foo が呼ばれるかを実行時に決定
print(animal.foo()) // 2 or 3
```

プロトコル型変数を介すとこのようなオーバーヘッドが発生します。 Swift のコードを書くときに Java のようなスタイルでプロトコル型変数や引数・戻り値を多用すると、コード中のありとあらゆる箇所で余計なオーバーヘッドが生じてしまうわけです。

Swift でプロトコル型変数（や引数・戻り値）を使う必要がない場所であえてプロトコル型変数を使うのは、 Java で `int` で良いのにあえて `Integer` を使って無駄なボクシングを発生させるようなものです。次のコードが無駄であることに異論がある人はいないでしょう。

```java
// Java
static Integer triple(Integer number) {
    return number * 3;
}
```

`Integer` ではなく `int` を使って次のように書くべきです。

```java
// Java
static int triple(int number) {
    return number * 3;
}
```

これが、僕が Swift においてプロトコル型変数（や引数・戻り値）の利用を本当に必要な場合以外は避けるべきだと考える理由です。

## プロトコルを型として使わずにどのように抽象化するか

とは言え、 Java でインタフェース型変数（や引数・戻り値）を使ってコードを抽象化するのは「本当に必要な場合」のように思えます。 Swift でプロトコル型変数（や引数・戻り値）を使うのは「本当に必要な場合」ではないのでしょうか？

Java 等の感覚では、プロトコル型変数を使わずにコードを書くのは難しいように思えます。しかし、大抵のケースはプロトコル型変数を使わなくても同じことができます。

たとえば、先程の `Cat` や `Dog` を抽象化して処理を記述する場合を考えてみましょう。

```swift
protocol Animal {
    func foo() -> Int
}
struct Cat: Animal {
    func foo() -> Int { return 2 }
}
struct Dog: Animal {
    func foo() -> Int { return 3 }
}
```

`Animal` を使う関数 `useAnimal` は、プロトコル型引数を使って書くと次のようになります。

```swift
func useAnimal(_ animal: Animal) {
    print(animal.foo())
}
```

しかし、この関数はプロトコル型引数を使わなくても次のように書くことができます。

```swift
func useAnimal<A: Animal>(_ animal: A) {
    print(animal.foo())
}
```

どちらの場合でも処理の内容は同じです。決定的に違うのは、後者の `A` は `Animal` というプロトコル型ではなく、常に具体的な何らかの型を表すということです。

実際にコンパイラは、最適化の過程でジェネリックな関数やメソッドの型パラメータを具体的な型に展開する場合があります。これを **_特殊化（ Specialization ）_** といいます。前述の `func useAnimal<A: Animal>(_ animal: A)` は、特殊化されると次のように書かれているのと等価になります。

```swift
func useAnimal(_ animal: Cat) {
    print(animal.foo())
}

func useAnimal(_ animal: Dog) {
    print(animal.foo())
}

...
```

これなら、引数 `animal` は常に具象型で宣言されているので、 existential container の出番はありません。

実際に、 Swift の標準ライブラリでもほとんどの API は `func useAnimal(_ animal: Animal)` ではなく `func useAnimal<A: Animal>(_ animal: A)` のスタイルで書かれています。つまり、 **Swift では多くのケースにおいて、プロトコル型変数（や引数・戻り値）は「本当に必要」なものではなく避けることができるものなのです**。

### ジェネリック関数では書けない場合

ただし、いつもこの方法が使えるとは限りません。どのような場合に使えず、そんなときはどうしたらいいかを説明します。

`Animal` の配列を受け取り処理を行う `useAnimals` という関数を考えてみましょう。この場合、 `animals` には `Cat` と `Dog` が混ざった配列を渡すことができます。

```swift
func useAnimals(_ animals: [Animal]) {
    animals.forEach { print($0.foo()) }
}

useAnimals([Cat(), Dog()]) // OK ✅
```

しかし、 `Animal` というプロトコル型を使わずにジェネリクスで書こうとすると、 `[A]` の `A` は一つの型に定まってしまうので `Cat` と　`Dog` を同時に入れることはできません。

```swift
func useAnimals<A: Animal>(_ animals: [A]) {
    animals.forEach { print($0.foo()) }
}

useAnimals([Cat(), Dog()]) // NG ⛔️
```

そういうときにはプロトコル型を使うしかありません。しかし、 `associatedtype` を持つプロトコルは型として用いることができません。そのような場合は、ワークアラウンドとして type erasure が用いられています。

たとえば、 `Sequence` プロトコルには `struct AnySequence<Element>` という type erasure が標準ライブラリで提供されています。

```swift
let array: Array<Int> = [2, 3, 5]
let set: Set<Int> = [7, 11]

var sequence: AnySequence<Int>
sequence = AnySequence(array)
sequence = AnySequence(set)
```

このように、 `AnySequence<Element>` は `Sequence<Element>` の代わりとして振る舞います。

個人的には、この `AnySequence` のような type erasure を用いる方式はなかなか良いバランスなのではないかと思っています。

`associatedtype` を持たないプロトコルならそのまま型として用いることができますが、ちょっと手軽すぎます。見た目上も普通の型と見分けが付きません。

```swift
// Animal はプロトコル？具象型？🤔
let animal: Animal = Cat()
```

プロトコル型を例外的なものとして意識的に扱うためには、また、 `AnySequence` などと統一するためにも、あえて次のような書き方をした方がいいんじゃないかとすら思います。

```swift
protocol Animal {}
struct Cat: Animal {}
typealias AnyAnimal = Animal

let animal: AnyAnimal = Cat()
```

実は過去に、 existential を表すのに、 `Animal` のようにプロトコルを型として記述する記法ではなく、 `Any<Animal>` のような記法を採用するチャンスがありました。

[SE-0095](https://github.com/apple/swift-evolution/blob/master/proposals/0095-any-as-existential.md) の変更によって、 Swift 3 からプロトコル `P1`, `P2` の両方に適合する型を `P1 & P2` と書くことができるようになりました。しかし、当初このプロポーザルは `P1 & P2` ではなく `Any<P1, P2>` という記法を提案していました。 N 個のプロトコルに対して `Any<P1, P2, ...>` と書くなら、一つのプロトコルに対して `Any<P1>` と書けるべきです。 `Any<P1>` は単に `P1` と書くのと同じ意味になってしまうので、当初のプロポーザルの記法が採用されていれば、 `P1` と書くのはやめて `Any<P1>` に統一しようという方向もあり得たかもしれません。

`Any<Animal>` という記法であれば、それが existential であることはひと目でわかります。この記法が採用されなかったことは残念です。

```swift
protocol Animal {}
struct Cat: Animal {}

let animal: Any<Animal> = Cat()
```

さらにおもしろいことに、当初のプロポーザルは [`associatedtype` を持つプロトコルを existential として扱うための記法](https://github.com/apple/swift-evolution/blob/a4356fee94c06181715fad83aa61e923eb73f8ec/proposals/0095-any-as-existential.md#any-vs-any)にも言及しています。

```swift
let array: Array<Int> = [2, 3, 5]
let sequence: Any<Sequence where .Element == Int> = array
```

`Sequence` のように `associatedtype` を持つプロトコルでも変数や引数・戻り値の型として扱えるようにするための言語仕様である [generalized existential](https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials) について、 Swift のジェネリクスの今後について述べられたドキュメント ["Generics Manifesto"](https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md) で言及されていますが、 SE-0095 の記法（ `Any<...>` ）を元にしています。 `P1 & P2` が採用されてしまった今となっては、 generalized existential にどのような記法を採用するのか悩ましそうです。

```swift
let array: Array<Int> = [2, 3, 5]
let sequence: Sequence where .Element == Int = array // 読みにくい
```

このあたりからも、この前 Discord の swift-developers-japan で話題になっていた [ABI 安定化前に generalized existential はやらないという話](https://forums.swift.org/t/status-of-generalized-existentials/13982/10) からも、僕は generalized existential は当分実現しないんじゃないかと思っています。

generalized existential が実現されるまでは、 `AnySequence` のような type erasure を使うしかありません。 `Sequence` については `AnySequence` を使っていれば問題ないんですが、自作のプロトコルに対して `AnyFoo` を用意しようとすると大変です。

type erasure の実装方法については、 @omochimetaru の ["Swift の Type Erasure の実装パターンの紹介"](https://qiita.com/omochimetaru/items/5d26b95eb21e022106f0) にまとめられています。

一度実装してみるとわかりますが、めちゃくちゃ面倒です。これをやらないといけないなんて何か言語仕様おかしいだろという気持ちになります。なので、僕は existential の利用は最小限に留めるべきだとは考えていますが、どうしても必要なときに `AnyFoo` を実装する手間をなくす方法として考えるなら generalized existential を導入するのもありかなと思います。

ただ、実際に `AnyFoo` を実装したくなることは稀なので、必要なときに `AnyFoo` を実装するという現状（ Swift 4.1 時点）でも十分ではないかとも思います。 generalized existential で言語仕様を複雑にすることと、必要になったときに都度 `AnyFoo` を実装する手間を天秤にかけると、後者を採るのもありではないでしょうか。

僕が Swift の発展の方向性として良い方法だと思っているのは、 `Codable` や `Equatable` のようにコード生成で `AnyFoo` を自動生成できるようにすることです。その場合、 generalized existential で言語仕様が複雑になることもなく、現状を踏襲したまま手間だけを軽減できます。

いずれにせよ、現状（ Swift 4.1 ）では必要に応じて `AnyFoo` のような type erasure を実装するしかありません。しかし、普通はそんな事態には滅多に遭遇しないでしょう。

## Swift のプロトコルがジェネリクスをサポートしない理由

前置きの説明が長くなりましたがここからが本題です。

ここまで、プロトコル型変数（や引数・戻り値）はできるだけ避け、本当に必要なときに最小限に留めて使用すべきということを述べました。そして、抽象化のためにプロトコル型が必要になることは少なく、大抵は `func useAnimal(_ animal: Animal)` の代わりに `func useAnimal<A: Animal>(_ animal: A)` のように書くことで、プロトコル型を回避できることを説明しました。

しかし、それだけでプロトコルがジェネリクスをサポートすべきでない理由にはなりません。

確かに、プロトコルがジェネリクスをサポートして次のようなコードが Swift で氾濫するのは避けたいところです。

```swift
let array: Array<Int> = [2, 3, 5]
let sequence: Sequence<Int> = array // これは避けたい
```

しかし、これは generalized existential が使えるようになったとして、それを乱用すべきでないというのと同じ程度の意味しか持ちません。

```swift
let array: Array<Int> = [2, 3, 5]
let sequence: Any<Sequence where .Element == Int> = array // これも避けたい
```

この二つは記法が異なるだけで本質的には同じことを意味しています。 generalized existential の方が記法が複雑なため、カジュアルに使いづらく乱用を防ぎやすいと考えることはできます。しかし、類似した二つのものに異なる記法を採用するより、一つの記法にまとめた方がシンプルで良いという考えもあり得ます。何か決定的に、ジェネリクスの型パラメータと `associatedtype` を区別しておかないといけない理由がないと、プロトコルがジェネリクスをサポートしない理由にはなりません。

この理由を探るために、仮にプロトコルにジェネリクスが許されているとして、 Swift の標準ライブラリをジェネリックなプロトコルで書くと何が起こるかを見てみましょう。

ここが重要ですが、これから Swift の標準ライブラリをジェネリックなプロトコルで書き直すに当たって、 **API の引数や戻り値にプロトコル型は使わない** ようにします。ここまでの長い前置きは、このルールを設けるためのものです。次のような問題設定です。

1. Swift ではプロトコル型変数（や引数・戻り値）を使うことにデメリットがある
2. プロトコル型は本当に必要な場合に限って必要最小限利用すべき
3. メソッドの引数や戻り値にプロトコル型を使いたい場合、大抵は書き換えられるので「本当に必要」でないことが多い
  - `func useAnimal(_ animal: Animal)` → `func useAnimal<A: Animal>(_ animal: A)`
4. たとえプロトコルがジェネリクスをサポートしても、 Java のようなスタイルでプロトコル型を多用するのではない
5. その上で、標準ライブラリをジェネリクスで書いてみるとどうなるか

### `IteratorProtocol`

それでは、 `IteratorProtocol` から始めましょう。 `IteratorProtocol` は標準ライブラリで次のように宣言されています。

```swift
// associatedtype を使った場合
protocol IteratorProtocol {
    associatedtype Element
    mutating func next() -> Element?
}
```

`IteratorProtocol` は `associatedtype` として `Element` を持ち、次の `Element` を返すメソッド `next` を持ちます。イテレータはシーケンスから一つずつ値を取り出すためのものなので、とても自然な設計です。

普通は `for` 文の中で暗黙的に利用されるので直接 `IteratorProtocol` を使うことは少ないですが、直接使用すると次のようになります。

```swift
let array = [2, 3, 5]
var iterator = array.makeIterator()

iterator.next() // Optional(2)
iterator.next() // Optional(3)
iterator.next() // Optional(5)
iterator.next() // nil
```

`next` が `mutating func` なのは、このイテレータが値型のときに必要だからです。 `next` が呼び出される度に異なる値（次の要素を）返そうとすると、自分自身の状態を変更しないといけません。

この `IteratorProtocol` をジェネリクスで書くと次のようになります。

```swift
// ジェネリクスを使った場合
protocol IteratorProtocol<Element> {
    mutating func next() -> Element?
}
```

特に何の問題もありません。むしろ `associatedtype` よりもすっきりして感じられます。

### `Sequence`

次は、 `IteratorProtocol` を使う `Sequence` プロトコルを考えてみましょう。 `Sequence` は `makeIterator` メソッドを持ち、イテレータを生成して返します。

標準ライブラリでは、 `associatedtype` を使って次のように宣言されています（話をシンプルにするために少し単純化しています）。

```swift
// associatedtype を使った場合
protocol Sequence {
    associatedtype Element
    associatedtype Iterator: IteratorProtocol where Iterator.Element == Element

    func makeIterator() -> Iterator
}
```

コードがいきなり複雑になりました。 `Sequence` は `Element` に加えて、 `Iterator` という `associatedtype` を持っています。

`Iterator` は `makeIterator` の戻り値の型として必要になる `associatedtype` です。ここに `IteratorProtocol` と書くことはできません。引数や戻り値にプロトコル型を使わないというルールに違反することもありますが、そもそも `IteratorProtocol` は `associatedtype` を持っているのでプロトコル型として利用することができません。そのため、わざわざ `Element` とは別に `Iterator` という `associatedtype` を宣言する必要が生じます。

この `Iterator` は、 `Sequence` に適合した具象型では具体的な型となります。たとえば、 `Array.Iterator` は `IndexingIterator<Array<Element>>` です。

```swift
let numbers: Array<Int> = [2, 3, 5]
var iterator: IndexingIterator<Array<Int>> = numbers.makeIterator()

iterator.next() // Optional(2)
iterator.next() // Optional(3)
iterator.next() // Optional(5)
iterator.next() // nil
```

`Sequence` の `Element` と `Iterator.Element` で不整合が起こってはいけないので、 `Iterator` には `where Iterator.Element == Element` という条件が付与されています。この条件がないと、 `Element` は `Int` だけど `Iterator` は `Double` を返すような変な `Sequence` が実装できてしまいます。

Java の `Iterable` インタフェースはもっとシンプルです。 Swift の `Sequence` プロトコルを Java の `Iterable` っぽく書くと次のようになります。

```swift
// ジェネリクスを使って Java 風に書いた場合
protocol Sequence<Element> {
    func makeIterator() -> IteratorProtocol<Element>
}
```

`Sequence` は要素のシーケンスを表すので型パラメータ `Element` （要素）を持ち、 `makeIterator` でその要素を取り出すための `IteratorProtocol<Element>` を返す。とてもシンプルです。

しかし、これはルール違反です。プロトコル型 `IteratorProtocol<Element>` を `makeIterator` の戻り値の型として使ってしまっています。プロトコル型を戻り値に使わないようにするにはどうすればいいでしょうか？

型パラメータ `Iterator` を追加し、次のようになります。コードの内容も分量も、 `associatedtype` のときとほぼ同じです。これも、特に問題があるようには思えません。

```swift
// ジェネリクスを使った場合
protocol Sequence<Element, Iterator: IteratorProtocol<Element>> {
    func makeIterator() -> Iterator
}
```

### `Collection`

さて、次に `Sequence` を継承した `Collection` プロトコルを考えます。 `Collection` は `array[index]` のような形で要素にアクセスするための API を表すプロトコルです。

`Collection` は標準ライブラリでは次のように宣言されています（こちらも単純化しています）。

```swift
// associatedtype を使った場合
protocol Collection: Sequence {
    associatedtype Index

    subscript(position: Index) -> Element { get }
}
```

新たな `associatedtype` として `Index` が導入されています。 `Collection` のインデックスは `Int` とは限りません。ありとあらゆるインデックスの型に対応できるように、 `associatedtype` になっています。

これをジェネリクスを使って Java 風に書いてみると次のようになります。

```swift
// ジェネリクスを使って Java 風に書いた場合
protocol Collection<Element, Index>: Sequence<Element> {
    subscript(position: Index) -> Element { get }
}
```

シンプルですね。しかし、プロトコル型の引数・戻り値を禁止するために `Sequence` は `Element` と `Iterator` の二つの型パラメータを持つんでした。 `: Sequence<Element>` ではなく、 `: Sequence<Element, Iterator>` でないといけません。そのためには `Collection` も `Iterator` という型パラメータを持つ必要が生じます。

ジェネリクスを使って、かつ、プロトコル型の引数・戻り値を禁止すると、 `Collection` は次のようになります。

```swift
// ジェネリクスを使った場合
protocol Collection<
    Element,
    Iterator: IteratorProtocol<Element>,
    Index
>: Sequence<Element, Iterator> {
    subscript(position: Index) -> Element { get }
}
```

ちょっと辛くなってきました。 `associatedtype` のときと比べて記述量も多くなっています。一体何が原因でしょうか？

`associatedtype` で書いたときの `Collection` の宣言には一切 `Iterator` が現れません。 `Element` も、 `subscript` の戻り値として現れるだけで、その宣言はどこにも書かれていません。これは、プロトコルを継承したときに `associatedtype` も自動的に受け継がれるからです。しかし、ジェネリクスではすべての型パラメータを明示的に記述する必要があります。

引数や戻り値にプロトコル型を使わないというルールの元では、 `Iterator` のように、それらをすべて型パラメータで記述しなければいけません。そのため、プロトコル型を使いたいケースに遭遇する度に型パラメータが増え、大変なことになります。

### `Sequence` (2)

先程は省略しましたが、 `Sequence` の持つ `associatedtype` は `Element` と `Iterator` だけではありません。他に `SubSequence` という `associatedtype` も持っています。

`SubSequence` は `Sequence` の部分シーケンスを表すのに用いられます。たとえば、 `Sequence` の `prefix` メソッドは最初の N 個の要素だけを持つ部分シーケンスを返します。

部分シーケンスの型は `Sequence` と同じじゃないかと思うかもしれませんが、そうとは限りません。たとえば、 `Array` の `SubSequence` は `ArraySlice` です。

`prefix` の戻り値の型を `Sequence<Element>` と書くことができれば `Array<Element>` だろうと `ArraySlice<Element>` だろうと返すことができます。しかし、プロトコル型の戻り値を禁止するルールの元ではそれはできません。 `prefix` の戻り値の型は `associatedtype SubSequence` で表すことになります。

```swift
// associatedtype を使った場合
protocol Sequence {
    associatedtype Element
    associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
    associatedtype SubSequence: Sequence
        where Element == SubSequence.Element, SubSequence.SubSequence == SubSequence

    func makeIterator() -> Iterator
    func prefix(_ maxLength: Int) -> SubSequence
}
```

これをジェネリクスで書くと次のようになります。

```swift
// ジェネリクスを使った場合
protocol Sequence<
    Element,
    Iterator: IteratorProtocol<Element>,
    SubSequenceIterator: IteratorProtocol<Element>,
    SubSequence: Sequence<Element, SubSequenceIterator, SubSequence>
> {
    func makeIterator() -> Iterator
    func prefix(_ maxLength: Int) -> SubSequence
}
```

`associatedtype` で書いた場合には `SubSequence` の `Iterator` については特に指定していませんが、ジェネリクスで書く場合にはこれも明示的に記述しなければなりません。

`Sequence` の `Iterator` と `SubSequence` の `Iterator` は同じ型で良さそうですが、異なる型にしたいケースもあります。実際に、 `Array` の `Iteartor` は `IndexingIterator<Array<Element>>` ですが、 `Array` の `SubSequence` である `ArraySlice` の `Iterator` は `IndexingIterator<ArraySlice<Element>>` という別の型です。 `SubSequence` に `Sequence` と異なる `Iterator` を指定できるようにするには、 `SubSequenceIterator` という新たな型パラメータを導入する必要があります。

そのため、プロトコル型の引数や戻り値を使わないというルールの元で、ジェネリクスを用いて `Sequence` を記述しようとすると、 `Sequence` は前述のような四つの型パラメータを持つ複雑なプロトコルになってしまいました。

### `Collection` (2)

`Collection` はさらに悲惨なことになります。

`associatedtype` で書く場合には、 `SubSequence` はどこにも現れません。 `Sequence` から自動的に受け継がれるからです。

```swift
// associatedtype を使った場合
protocol Collection: Sequence {
    associatedtype Index

    subscript(position: Index) -> Element { get }
}
```

しかし、ジェネリクスを使うと次のようになります。めちゃくちゃ長いです。

```swift
// ジェネリクスを使った場合
protocol Collection<
    Element,
    Iterator: IteratorProtocol<Element>,
    SubSequenceIterator: IteratorProtocol<Element>,
    SubSequence: Sequence<Element, SubSequenceIterator, SubSequence>,
    Index
>: Sequence<
    Element,
    Iterator,
    SubSequenceIterator,
    SubSequence
> {
    subscript(position: Index) -> Element { get }
}
```

おっと、 `Collection` はもう一つ `Indices` という `associatedtype` を持つんでした。 `indices` プロパティでインデックスのコレクションを返すためです。

```swift
// associatedtype を使った場合
protocol Collection: Sequence {
    associatedtype Index
    associatedtype Indices: Collection = DefaultIndices<Self>
        where Indices.Element == Index,
              Indices.Index == Index,
              Indices.SubSequence == Indices

    subscript(position: Index) -> Element { get }
    var indices: Indices { get }
}
```

これをジェネリクスで書いてみましょう。

```swift
// ジェネリクスを使った場合
protocol Collection<
    Element,
    Iterator: IteratorProtocol<Element>,
    SubSequenceIterator: IteratorProtocol<Element>,
    SubSequence: Sequence<Element, SubSequenceIterator, SubSequence>,
    Index,
    IndicesIterator: IteratorProtocol<Element>,
    Indices: Collection<
        Element,         // Element
        IndicesIterator, // Iterator
        IndicesIterator, // SubSequenceIterator
        Indices,         // SubSequence
        IndicesIterator, // IndicesIterator
        Indices          // Indices
    >
>: Sequence<
    Element,
    Iterator,
    SubSequenceIterator,
    SubSequence
> {
    subscript(position: Index) -> Element { get }
    var indices: Indices { get }
}
```

これぞ型パラメータ地獄です💀特に、 `SubSequence` や `Indices` のように再帰的なパラメータがあるとヤバイです。

### `MutableCollection`

しかし、さらに地獄なのは `Collection` が色々なプロトコルのスーパープロトコルなことです。 `Collection` を継承しているプロトコルには次のようなものがあります。

```swift
protocol BidirectionalCollection: Collection
    where SubSequence: BidirectionalCollection,
          Indices: BidirectionalCollection { ... }

protocol LazyCollectionProtocol: Collection, LazySequenceProtocol { ... }

protocol MutableCollection: Collection
    where SubSequence: MutableCollection { ... }

protocol RangeReplaceableCollection: Collection
    where SubSequence: RangeReplaceableCollection { ... }
```

たとえば、 `MutableCollection` は標準ライブラリでは `associatedtype` を使って次のように宣言されています（例によって単純化しています）。

```swift
// associatedtype を使った場合
protocol MutableCollection: Collection
    where SubSequence: MutableCollection
{
  subscript(position: Index) -> Element { get set }
}
```

`MutableCollection` は `array[index] = 42` のように状態の変更を受け付けるので、 `subscript` の宣言に `set` が追加されています。 `Collection` との差分だけが書かれていてシンプルです。

これと同じことをジェネリクスで書くと次のようになります。もはや、ちゃんと書けているか自信がありません（少なくとも `Index` が宣言前に使われているので、型パラメータの順序は入れ替えないといけないはずです）。

```swift
// ジェネリクスを使った場合
protocol MutableCollection<
    Element,
    Iterator: IteratorProtocol<Element>,
    SubSequenceIterator: IteratorProtocol<Element>,
    SubSequenceIndicesIterator: IteratorProtocol<Index>,
    SubSequenceIndices: Collection<
        Element,                    // Element
        SubSequenceIndicesIterator, // Iterator
        SubSequenceIndicesIterator, // SubSequenceIterator
        SubSequenceIndices,         // SubSequence
        SubSequenceIndicesIterator, // IndicesIterator
        SubSequenceIndices          // Indices
    >,
    SubSequence: MutableCollection<
        Element,                    // Element
        SubSequenceIterator,        // Iterator
        SubSequenceIterator,        // SubSequenceIterator
        SubSequenceIndicesIterator, // SubSequenceIndicesIterator
        SubSequenceIndices,         // SubSequenceIndices
        SubSequence,                // SubSequence
        Index,                      // Index
        SubSequenceIndicesIterator, // IndicesIterator
        SubSequenceIndices          // Indices
    >,
    Index,
    IndicesIterator: IteratorProtocol<Element>,
    Indices: Collection<
        Element,         // Element
        IndicesIterator, // Iterator
        IndicesIterator, // SubSequenceIterator
        Indices,         // SubSequence
        IndicesIterator, // IndicesIterator
        Indices          // Indices
    >
>: Collection<
    Element,
    Iterator,
    SubSequenceIterator,
    SubSequence,
    Index,
    IndicesIterator,
    Indices
> {
    subscript(position: Index) -> Element { get set }
}
```

`subscript` の `set` を書き足すためだけにこれを書くのはやってられません。

このように、 **プロトコル型の引数や戻り値を用いないというルールを定めると、ジェネリクスの記法で書くのは非現実的** です。

ジェネリクスでも、 `associatedtype` のように型パラメータを暗黙的に受け継ぐ言語仕様にするという方法も考えられるかもしれません。しかし、そもそもプロトコル型変数（や引数・戻り値）はできるだけ避けたいものなので、具象型とプロトコル型で同じジェネリクスの記法を採用するのは好ましくないという見方がありました。それでも、ジェネリクス（の型パラメータ）と `associatedtype` という類似の仕組みを異なる構文で提供するよりは、ジェネリクスという統一的な構文にした方がシンプルではないかという問いについて考えて来ました。

その結果、 Swift の標準ライブラリが行っていることをジェネリクスの記法で表現しようとすると型パラメータ地獄に陥ることがわかりました。それであれば、 **そもそも区別しておきたいものなんだから、型パラメータと `associatedtype` という異なる構文として提供する方が理に適っています**。あえて、ジェネリクスの構文を魔改造して、無理やり型パラメータを省略・継承できるようにする理由はありません。

これが、僕が Swift の現状を元に推察した、 Swift のプロトコルがジェネリクスをサポートしない理由です。

プロトコルがジェネリクスをサポートせず、型パラメータの代わりに `associatedtype` を用いることで、値型中心の Swift にフィットした API をシンプルに記述できるわけです。

## まとめ

- 値型中心の Swift でプロトコル型変数（や引数・戻り値）を多用したコードを書くとオーバーヘッドが生じる
- （ `Animal` がプロトコルだとして） `func foo(_ animal: Animal)` ではなく `func foo<A: Animal>(_ animal: A)` と書くことでプロトコル型引数・戻り値を避けられる場合が多い
- プロトコルでジェネリクスがサポートされていたとしても、プロトコル型引数・戻り値を使わずに標準ライブラリを再現しようとすると型パラメータ地獄になる💀