LoginSignup
7
7

More than 5 years have passed since last update.

Protocol Extensions のメソッドディスパッチについての誤解

Last updated at Posted at 2016-04-26

概要

Swift2.0 で追加された Protocol Extensions のメソッドディスパッチの振る舞いが、混乱しやすい物だと感じたので、その振る舞いについてまとめておきます。

Protocol Extensions の振る舞い

protocol SomeProtocol {
}

extension SomeProtocol {
    func someMethod() {
        print("call someMethod of SomeProtocol")
    }
}

struct SomeStruct : SomeProtocol {
    func someMethod() {
        print("call someMethod of SomeStruct")
    }
}

このような定義があるとき

let a = SomeStruct()
a.someMethod() // => "call someMethod of SomeStruct"

SomeStruct型の変数asomeMethod呼び出しの結果、
SomeStructに定義されたsomeMethodが呼び出されます。
これは多くの人が期待する振る舞いだと思います。

では、

let b:SomeProtocol = a
b.someMethod() // => ?

このようにSomeStruct型の変数aを代入したSomeProtocol型の変数bを宣言し、そのbsomeMethodを呼び出すとなんと出力されるでしょうか。
少なくとも私は"call someMethod of SomeStruct"と出力されることを期待していたのですが、実際は"call someMethod of SomeProtocol"が出力されます。

つまり現状 Protocol Extensions のメソッド呼び出しは、polymorphic な振る舞いをしないようです。

Default Implementations

一方、Protocol の Default Implementations においては、上記とはメソッドディスパッチの振る舞いが異なります。

protocol SomeProtocol {
    func someMethod()
}

extension SomeProtocol {
    func someMethod() {
        print("call someMethod of SomeProtocol")
    }
}

struct SomeStruct : SomeProtocol {
    func someMethod() {
        print("call someMethod of SomeStruct")
    }
}


let b:SomeProtocol = SomeStruct()
b.someMethod() // => "call someMethod of SomeStruct"

これらの挙動を知らずに、以下のようなコードを書くと、想像しているものとは異なる振る舞いに悩まされるのでご注意ください。

protocol SomeDelegate {
}

extension SomeDelegate {
    func optionalMethod() {
        // nothing to do.
    }
}

class SomeClass: SomeDelegate {
    func optionalMethod() {
        print("optionalMethod") // ← 呼ばれない
    }
}

let delegate: SomeDelegate = SomeClass()
delegate.optionalMethod()

参考にしたページ

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7