0

I'm implementing a structure composed as following:

protocol ProtocolA {
  func doStuff()
}

protocol ProtocolB { }

extension ProtocolA {
  func doStuff() {
    print("From protocol A")
  }
}

extension ProtocolA where Self: ProtocolB {
   func doStuff() {
     print("From protocol B")
   }
}

And I have the following classes:

class MyClassA: ProtocolA {
   func letsDoSomething() {
      self.doStuff()
   }
}

class MyClassB: MyClassA, ProtocolB {
}

What happen is:

let ia = MyClassA()
ia.letsDoSomething() // From protocol A (OK!)

let ib = MyClassB()
ib.letsDoSomething() // From protocol A (Wrong!)

Of course I do not expect to have the second answer.

As specified in the Swift Programming Launguage guide:

If a conforming type satisfies the requirements for multiple constrained extensions that provide implementations for the same method or property, Swift will use the implementation corresponding to the most specialized constraints.

Why the class ib that is conform to ProtocolB doesn't call the most specialized extension implementation?

I know that the calling class is still MyClassA but since the instance is from MyClassB that is conform to the protocol ProtocolB I still expect to have the most specialized implementation to be called.

GrizzlyBear
  • 1,098
  • 1
  • 13
  • 27
  • Compare point #2 of https://stackoverflow.com/a/42286148/2976878 and https://stackoverflow.com/a/44706021/2976878. `MyClassB` doesn't get its own conformance to `ProtocolA`; it relies on `MyClassA`'s conformance. – Hamish Aug 28 '17 at 12:45
  • I agree that's why I expect to have as result `\\ From protocol B`. Don't you agree? – GrizzlyBear Aug 28 '17 at 12:58
  • 1
    No; `MyClassB` relies on `MyClassA`'s conformance to `ProtocolA`. `MyClassA` does not conform to `ProtocolB`, so the constrained extension method cannot satisfy its conformance. Therefore the unconstrained extension method satisfies its conformance, and thus is the one that's called. – Hamish Aug 28 '17 at 13:13

1 Answers1

1

The problem is MYClassB is inherited from MyClass A. Swift’s method dispatch rules this child class’ implementation is never called and the default implementation is always used in case of protocol conformance. Try the same case like this

class MyClassA: ProtocolA {
    func letsDoSomething() {
        self.doStuff()
    }
}

class MyClassB: ProtocolA, ProtocolB {
}


let ia = MyClassA()
ia.letsDoSomething() // From protocol A (OK!)

let ib = MyClassB()
ib.doStuff() // From protocol A (Wrong!)
  • The problem is exactly using the implementation of `letsFoSomething` that is already implemented in `MyClassA` but replacing the behavior of `doStuff()` by using the constrained implementation of `extension ProtocolA where Self: ProtocolB`. Following your solution I need to copy-paste the shared code contained in `lestDoSomething`. I'm not sure I explained correctly the point. Is it clear? Do you have any idea how this can be achieved without copy-pasting the implementation of `ia.letsDoSomething()`? – GrizzlyBear Aug 29 '17 at 07:42