Swift の protocol における Interface と Method の違いを理解しよう

# はじめに
本記事は今月頭に開かれた Otemachi.swift x Kyobashi.swift 合同勉強会で[発表した資料](https://speakerdeck.com/lovee/protocol-to-class-to-subclass)をベースに作成しております。

# 本題
常識かと思いますが、下記のような二つの protocol 宣言は全く別物だということを常に意識せねばなりません。

```swift:ProtocolA
protocol SomeProtocol {
	func printSelf()
}

extension SomeProtocol {
	func printSelf() {
		print("SomeProtocol")
	}
}
```

```swift:ProtocolB
protocol SomeProtocol {
	//func printSelf()
}

extension SomeProtocol {
	func printSelf() {
		print("SomeProtocol")
	}
}
```

一行だけの違いですが、`protocol SomeProtocol` の定義に Interface の宣言があるかどうかで、後の extension での実装の振る舞いは完全に別物になります。どう違うかというと、下記の例を読めばわかりやすいかと

```swift:ProtocolA
protocol SomeProtocol {
	func printSelf()
}

extension SomeProtocol {
	func printSelf() {
		print("SomeProtocol")
	}
}

class SomeClass: SomeProtocol {
	func printSelf() {
		print("SomeClass")
	}
}

let sc = SomeClass()

sc.printSelf() // 出力：SomeClass

(sc as SomeProtocol).printSelf() // 出力：SomeClass
```

```swift:ProtocolB
protocol SomeProtocol {
	
}

extension SomeProtocol {
	func printSelf() {
		print("SomeProtocol")
	}
}

class SomeClass: SomeProtocol {
	func printSelf() {
		print("SomeClass")
	}
}

let sc = SomeClass()

sc.printSelf() // 出力：SomeClass

(sc as SomeProtocol).printSelf() // 出力：SomeProtocol
```

ほとんど同じようなものですが、`protocol SomeProtocol` の宣言に `func printSelf()` を宣言した場合、`(sc as SomeProtocol).printSelf()` の出力結果は `class SomeClass` に実装したものになりますが、そうでない場合は `extension SomeProtocol` に実装したものになります。

なぜこのような違いがあるかというと、protocol の宣言時に宣言した関数は、この protocol の Interface（以下 PI と呼びます）となります。この protocol を準拠した class もしくは struct は、すべてこの PI があることが保証されています。ただし、extension ではこの PI のデフォルト実装があるので、もし準拠した class か struct にこの PI の実装を書いてなければ、extension で定義した実装を流用します。一方、宣言時にこの関数を宣言せず、extension でだけこの関数を実装した場合、これは PI としてのデフォルト実装ではなく、この protocol 固有の Method（以下 PM と呼びます）となります。

従って、`(sc as SomeProtocol).printSelf()` を呼び出す時、`ProtocolA` の場合は PI を呼び出しているので、extension のデフォルト実装関係なく、本来の実装である `SomeClass` の `printSelf()` を呼び出すが、`ProtocolB` の場合は PM を呼び出すことになります。

ちなみに PM の呼び出しは[こちらのスライド](https://speakerdeck.com/nhamada/swiftniokerumethod-dispatchnituite)を読めばわかる通り、静的 Dispatch となります。

# 発展
先ほど PI と PM の違いについて論じましたが、PM は静的 Dispatch なので何も難しいことはないですが、問題は PI の実装と class の継承が同時に入って来た場合どうなるのかというと、話がややこしくなります。

ちょっと複雑なコードになりますが、こちらをごらんください：

```swift
protocol SomeProtocol {
	func printSelf()
}

extension SomeProtocol {
	func printSelf() {
		print("SomeProtocol")
	}
}

class SomeClass: SomeProtocol {
	
}

class SomeSubClass: SomeClass {
	func printSelf() {
		print("SomeSubClass")
	}
}

class Parent {
	let someClass: SomeClass
	// init(someClass: SomeClass) { ... }
	func printSelf() {
		someClass.printSelf()
	}
}

let ssc = SomeSubClass()
let p = Parent(someClass: ssc)

ssc.printSelf() // 出力：SomeSubClass
p.printSelf() // 出力：？

/* 選択肢
A：SomeProtocol
B：SomeClass
C：SomeSubClass
*/
```

簡単に説明しますと、先ほどの ProtocolA の場合と同じように、`protocol SomeProtocl` に `func printSelf()` という PI を宣言しました。そして `extension SomeProtocol` にこの `printSelf()` のデフォルト実装をしました。ここで `class SomeClass` を `SomeProtocol` に準拠させました。ただし `printSelf()` の独自実装を行なっていないので当然ながら `printSelf()` は `SomeProtocol` のデフォルト実装になります。ここでさらに `SomeClass` を継承した `SomeSubClass` を登場させます。継承なので当然 `SomeSubClass` もスーパークラスと同じように `SomeProtocol` に準拠しています。なのでこの `SomeSubClass` に `printSelf()` を独自実装させてみました。ここでさらに `class Parent` という新たなクラスを登場させます。このクラスには `someClass` という `SomeClass` 型のプロパティーがあり、`Parent` が `printSelf()` を呼び出すと、`someClass.printSelf()` を実行させます。ここで `Parent` の `someClass` プロパティーが `SomeSubClass` のインスタンス `ssc` の場合、`Parent` の `printSelf()` の出力は果たしてどうなるのでしょうか？

実は発表のとき、この質問を当時現地にいた参加者に投げてみたところ、意外なことに正解者が一人もいませんでした（筆者の予想では多分 A と C で半々くらいになるんじゃないかと思ったのですが）…

ところでここまで読んだ読者の皆さんはどれが正解だと思いますか？

まあ正解を発表する前に、まず選択肢を見ていきましょう。A：SomeProtocol は PI のデフォルト実装、B：SomeClass は前のコードに書いた `SomeClass` の独自実装ですがここでそもそも登場してないのでまず可能性としてはありえないです。そして最後の C：SomeSubClass は今回のコードで書いた `SomeSubClass` の独自実装です。

ここで `p.printSelf()` を呼び出している際、実行されているのは `P#someClass.printSelf()` ですので、言い換えれば `(ssc as SomeClass).printSelf()` と同価です。

普通クラスを継承したとき、きちんと正しい振る舞いをさせるために、仮に継承した親クラスとして実行しても、実際行われているのは自分自身の実装になります。例えば

```swift
class Super {
	func printSelf() {
		print("I'm Super!")
	}
}

class Sub: Super {
	override func printSelf() {
		print("I'm Sub!")
	}
}

let sub = Sub()
(sub as Super).printSelf() // 出力：I'm Sub!
```

こちらのコードを実行し、`sub` を `Super` として `printSelf()` を呼び出しても、呼び出されているのは `Sub` で実装した `print("I'm Sub!")` です。ですので逆にいうと、`ssc.printSelf()` であろうか、`(ssc as SomeClass).printSelf()` であろうか、出力結果は同じ、`SomeSubClass` が実装した `print("SomeSubClass")` になるはず。なので、正解は C：SomeSubClass。そう思いませんか？

そう思うみなさんは実際このコードを Playground で実行して見ましょう。驚きの結果がおまちしております。

そう、本当の正解は A：SomeProtocol です。

なぜそうなったのでしょうか。実は `class SomeClass` で `func printSelf()` を独自実装しなかったため、`SomeClass` の `SomeProtocol` としての `printSelf()` はすでに `SomeProtocol` のデフォルト実装で確定されました。`SomeSubClass` が実装した `func printSelf()` は、`SomeProtocol` の PI ではなく、`SomeSubClass` 特有の `printSelf()` です。つまり `SomeSubClass` の `printSelf()` は、`SomeProtocol` の `printSelf()` とは全く無関係です。

その証拠に、`SomeSubClass` の `func printSelf()` 実装に、`override` キーワードがないことをご注意ください。`SomeSubClass` は親のメソッドをオーバーライドしていないのです。だから、`(ssc as SomeClass).printSelf()` を呼び出す場合、プログラムはそもそも `ssc` には独自の `printSelf()` 実装があるのは知らず、`SomeClass` の `printSelf()` を呼び出し、しかし `SomeClass` は独自の `printSelf()` がないため、準拠した `SomeProtocol` の `printSelf()` のデフォルト実装を呼び出すことになります。

ですので当然、`(ssc as SomeProtocol).printSelf()` を呼び出しても、結果は同じ `print("SomeProtocol")` になります。

# だからなに
この protocol の振る舞いを知らないと、バグを生み出す可能性が出てきます。例えば何かのクラスを作ったとき、そのクラスが準拠したプロトコルのデフォルト実装で OK だとしても、自分を継承したサブクラスがそのデフォルト実装では足りない場合があります。ですので継承のことを考えて、仮に自分がデフォルト実装で OK でも、きちんと独自実装してデフォルト実装を呼び出しましょう。（もちろん継承させないように `final` をつけるのも一つの解決ですが

```swift
class SomeClass: SomeProtocol {
	func printSelf() {
		(self as SomeProtocol).printSelf()
	}
}
```

# 余談
実はこの仕様、以前にもすでに一度[混乱を起こしたことがあります](http://qiita.com/omochimetaru/items/17cdbb5a77972c82a781)