モダンなSwiftのExtension（TargetedExtensions）を実装するときハマったところ

# これはなに

- 独自の拡張メソッドを認識しやすく、かつ名前が被らないようにするため、`ex` をもつプロトコルを作成してそれに準拠させるという実装スタイルがある
- その実装をするときにハマったので共有

# モダンなSwiftのExtensionについて

　下記の記事を読めばOK。
　この記事に影響を受けて自分のプロダクトにもモダンなExtensionを実装しようとした

- http://qiita.com/motokiee/items/e8f07c11b88d692b2cc5
- http://tech.vasily.jp/entry/swift_modern_extensions

## どのような状況でエラーが起きたか

### `associatedtype` の名前が被っててエラー？

- 自分のアプリが `Kingfisher`を採用していて、`Kingfisher`のプロトコルの `typealias` が自分の定義したプロトコルの `associatedtype` と同じだったので、試しに変更するとエラーは解消された
- https://github.com/onevcat/Kingfisher/blob/master/Sources/String%2BMD5.swift#L32
- モダンな実装をしている外部ライブラリは `associatedtype CompatibleType` とか `typealias CompatibleType = Hoge` と書いてるのをよく見かけるので、そのまま参考にすると名前が被ってしまった

## エラーを再現してみる
- どうしてエラーになるのか理解するために playground で同じような状況を再現してみる
- ACompatible の `associatedtype` の名前が、BCompatible と被るので `error: type 'String' does not conform to protocol 'BCompatible'` とエラーがでる

```Error_Contents.swift 
import Foundation

struct AExample<Base> {
    let base: Base
    init(_ base: Base) {
        self.base = base
    }
}

struct BExample<Base> {
    let base: Base
    init(_ base: Base) {
        self.base = base
    }
}

protocol ACompatible {
    associatedtype CompatibleType // 名前が同じ
    
    var aEx: CompatibleType { get }
}

protocol BCompatible {
    associatedtype CompatibleType // 名前が同じ、別の名前に変えると正常に動作する
    
    var bEx: CompatibleType { get }
}

extension ACompatible {
    
    var aEx: AExample<Self> {
        return AExample(self)
    }
}

extension BCompatible {
    
    var bEx: BExample<Self> {
        return BExample(self)
    }
}

extension String: ACompatible { }
extension String: BCompatible { } // ここで error: type 'String' does not conform to protocol 'BCompatible' が出る

extension AExample where Base == String {
    var count: Int {
        return base.characters.count
    }
}

extension BExample where Base == String {
    var count: Int {
        return base.characters.count
    }
}

"hello".aEx.count
"bye".bEx.count
```

- エラーを直訳すると「String はプロトコル BCompatible に準拠していません」となる
- `extension String: BCompatible { }` で準拠してるのになんでだろうと結構悩んだ

## `associatedtype` の名前が被ってるからエラーという訳でもない？

- `associatedtype` の名前が同じだからエラーなのはイマイチ納得がいかないので色々と試すと、`associatedtype` の名前が同じでも正常に動作するパターンがあった
- ~~`ACompatibe` と `BCompatible` のジェネリクスを別名に変更したり（NonError_1_Contents.swift）~~ （追記：typoしてるだけでエラーになりました）
- `ACompatible` と `BCompatible` の Extension で ○Exのプロパティの型を同じにする（NonError_2_Contents.swift）と正常に動作する
- 下記のコードは playground で正常に動作する

```NonError_2_Contents.swift 
import Foundation

struct Example<Base> {
    let base: Base
    init(_ base: Base) {
        self.base = base
    }
}

protocol ACompatible {
    associatedtype CompatibleType
    
    var aEx: CompatibleType { get }
}

protocol BCompatible {
    associatedtype CompatibleType
    
    var bEx: CompatibleType { get }
}

extension ACompatible {
    
    // aEx も Example<Base> で型を宣言
    var aEx: Example<Self> {
        return Example(self)
    }
}

extension BCompatible {

    // bEx も Example<Base> で型を宣言    
    var bEx: Example<Self> {
        return Example(self)
    }
}

extension String: ACompatible { }
extension String: BCompatible { }

extension Example where Base == String {
    var count: Int {
        return base.characters.count
    }
}

"hello".aEx.count // 5
"bye".bEx.count // 3
````

## まとまってないけど、まとめ
- なんでこうなるのかと聞かれると、うまく説明できないのでまだ困っている
- またアクセス修飾子の違いで条件がいろいろ変わるので、正確に検証できているのかと言われると怪しい
- ひとまず、プロトコルの `associatedtype` は他のプロトコルのものと被らないようにした
- 詳しい人が教えてくれると嬉しい