Swift protocol method override

Please consider the following code:

protocol FooProtocol {
    func bar()
}

// default implementations for protocol requirements
extension FooProtocol {
    func bar() { print("default") }
}

// A class inheriting `FooProtocol`
class Foo: FooProtocol {
    
}

// Override the `bar` function
final class Bar: Foo {
    func bar() {
        print("bar")
    }
}

When I cast bar as any FooProtocol, bar.bar() prints "default"

let bar: (any FooProtocol) = Bar()
bar.bar()
// default

However, in the Foo class, if I implement the bar function,

class Foo: FooProtocol {
    // explicitly declare the function
    func bar() {
        (self as any FooProtocol).bar()
    }
}

// now need to override
final class Bar: Foo {
    override func bar() {
        print("bar")
    }
}

let bar: (any FooProtocol) = Bar()
bar.bar()
// bar

Could you explain this behavior please?

As even without Foo implementing the bar function, there is a default implementation. The function body (self as any FooProtocol).bar() should be redundant.

Any suggestions will be greatly appreciated!

PS, when implementing Bar.bar, Xcode would auto add the override keyword, and then emit the error that Method does not override any method from its superclass.

env

$ swift --version

swift-driver version: 1.113 Apple Swift version 6.0 (swiftlang-6.0.0.7.6 clang-1600.0.24.1)

Target: arm64-apple-macosx14.0

Using my second implementation, calling foo.bar() would cause recursion error.

That's because Swift resolves methods on protocol conformance statically. It finds default method only from protocol, and IIRC when first implementation in inheritance chain omits it, all child types will be resolved to the default implementation declared within the protocol.

You can search for this on forum, there were many topics over years that run into the same issue.

As far as I can tell, this is a long-standing question. You can find relevant threads in the forum, like this one: How to override a method of a superclass which uses default implementation from protocol extension?

This is the following decade-old bug:

3 Likes