How to override a method of a superclass which uses default implementation from protocol extension?

I came across this pitfall recently.

protocol P {
  func foo()
}

extension P {
  func foo () {
    print("P.foo")
  }
}

class Base: P {}

class Derived: Base {
  func foo() {
    print("Derived.foo")
  }
}

let obj: P = Derived()
obj.foo()   // prints "P.foo", instead of "Derived.foo"

It has been brought up several times in this forums, like this one: Default Protocol Implementation Inheritance Behaviour - The current situation and what/if anything should be done about it. But since this is still a problem in Swift 5.3, I'd like to know if there's an elegant solution?

BTW, I used the following trick, and I know this is "ugly".

protocol P {
   func foo()
}

protocol PWithDefault {
}

extension P where Self: PWithDefault {
  func fooDefault() {
    print("P.foo")
  }
}

class Base: P, PWithDefault {
  // have to explicit write out a dummy `foo` for overriding
 func foo() {
    fooDefault()
  }
}

class Derived: Base {
  override func foo() {
    print("Derived.foo")
  }
}

Still looking forward for this to be officially solved though.

You are right, this is a problem but not sure if there is a good solution. The reason the behavior exists is because extensions do not support polymorphism that includes compile time polymorphism. The answer to why is behind protocols being allowed by structs and enums and those cant'e be extended so dynamic dispatch capabilities are not needed.

The way it is evident is by the fact that even though you would like to think Base class knows foo is implemented because it implements the protocol P but still its child Derived doesn't needs to mark the foo as an overridden function.

The below code will work but I would think that it really doesn't solves your use case as you were probably trying to provide a default implementation (like an abstract class that doesn't exists in Swift)

**protocol** P {

func foo()

}

extension P {

func foo () {

print("P.foo")

}

}

class Base: P {

func foo () {}

}

class Derived: Base {

override func foo() {

print("Derived.foo")

}

}

let obj: P = Derived()

obj.foo() // prints "P.foo", instead of "Derived.foo"

A few videos at the below playlist also cover the polymorphism in swift: