Gotcha when overriding an extension method

If a protocol defines a method, and provides a default implementation in an extension, a class can override that method, and the override will be called for any reference to the instance, even if the reference's type is declared as the protocol. However, this doesn't seem to work if you try to override the method in a subclass that inherits the protocol from its parent and the parent doesn't override the method. Is it a bug in the language/compiler, or a known limitation? Blogs/tutorials about overriding extension methods don't seem to mention this.

Example:

protocol Proto {
    func hello()
}

extension Proto {
    func hello() {
        print("Hello from the fallback for \(Self.self)")
    }
}

class Base1: Proto {
    func hello() {
        print("Hello from Base1")
    }
}

class Base2: Proto {
}

class Sub1: Base1 {
    override func hello() {
        print("Hello from Sub1")
    }
}

class Sub2: Base2 {
    func hello() {
        print("Hello from Sub2")
    }
}

var p: Proto = Base1()
p.hello()
p = Base2()
p.hello()
p = Sub1()
p.hello()
p = Sub2()
p.hello()

Results in:

Hello from Base1
Hello from the fallback for Base2
Hello from Sub1
Hello from the fallback for Sub2

I would expect the last line to read:

Hello from Sub2

I believe it is a known bug/design bug that you cannot change the protocol requirement if one of super classes uses the default implementation, though I couldn't find where. The one in Sub2 declaration is to be treated as an unrelated function.

https://bugs.swift.org/browse/SR-103

3 Likes