Controlling extension points in protocols を読んだ

本記事は下記記事を読めば理解できるので原文を読もう。

www.hackingwithswift.com


昼間、夜に読んで具体的な利用ケースが思い浮かばなかった。忘れそうなので記事に残す。

開発環境

> swift --version
swift-driver version: 1.45.2 Apple Swift version 5.6 (swiftlang-5.6.0.323.62 clang-1316.0.20.8)
Target: x86_64-apple-macosx12.0

> xcodebuild -version
Xcode 13.3
Build version 13E113

モチベーション

プロトコルのデフォルト実装あたりを見ていたら、Controlling extension points in protocols – Hacking with Swift を教えてもらったので読んだ。

コード1

protocol Dog {
    func bark()
}

extension Dog {
    func bark() {
        print("ワン!")
    }
}

struct JapaneseDog: Dog {}
struct AmericanDog: Dog {
    func bark() {
        print("bow!")
    }
}


let dogs: [Dog] = [JapaneseDog(), AmericanDog()]
for dog in dogs {
    dog.bark()
}

// ワン!
// bow!

プロトコル Dogbark() のデフォルト実装がextension内で宣言されている。
JapaneseDog はデフォルト実装の bark() が実行され、AmericanDogbark() をオーバライドしたものが実行される。ここまでは理解できる。

コード2

protocol Dog {
//    func bark()
}

extension Dog {
    func bark() {
        print("ワン!")
    }
}

struct JapaneseDog: Dog {}
struct AmericanDog: Dog {
    func bark() {
        print("bow!")
    }
}


let dogs: [Dog] = [JapaneseDog(), AmericanDog()]
for dog in dogs {
    dog.bark()
}


// ワン!
// ワン!

プロトコルからメソッドの定義を除外すると、オーバーライドよりデフォルト実装が優先される。(そういう仕様だよと言われればそうなんだけど、直感に反する)

  • 適合型でメソッドをオーバーライドさせるには、プロトコルにメソッド定義を含める
  • 適合型でメソッドをオーバーライドさせないためには、プロトコルからメソッド定義を除外

いつ使うねん?感がある。開発における具体的な利用ケースが思いつかない。デフォルト実装の利用を強制(= オーバーライドさせない)させたい時に使うと言われればそうなのだが、オーバーライド自体は宣言できてしまうのでスッキリしない。SwiftLintで吸収できれば良いかなと思ったけどそこまでやるかなあみたいな気持ちになった。

参考