2

Consider this (rather tedious) code :

class SCell : NSObject {}
class SHeader : NSObject {}

class Cell : SCell {}
class Header : SHeader {}
struct Model {}

protocol PA {
    typealias Ce = SCell
    typealias He = SHeader
    func doThis(cell : PA.Ce,header : PA.He)
}

extension PA {
     func doThis(cell : PA.Ce,header : PA.He) {
        print("A's implementation")
    }
}

protocol PB:PA {

}

extension PB {
    func doThis(cell : PA.Ce,header : PA.He) {
        print("B's implementation")
    }
}

class A  : PA {
    func doSomethingElse() {
        self.doThis(cell: Cell(), header: Header())
    }
}

class B : A,PB {

}

class C : B {}

let c = C()
c.doSomethingElse()

To my surprise, this started printing out

"A's implementation"

I was expecting it to print "B's implementation" since doThis(cell:header) is overridden as a part of PBs default implementation. This surprisingly did not happen.

What's more interesting is that if I do this:

class B: A,PB {
    override func doSomethingElse() {
        self.doThis(cell: Cell(), header: Header())
    }
}

It started to print out

B's implementation

Why is this happening?

1 Answer 1

1

Protocol extensions don't do polymorphism, so in this case, they are not dynamically dispatched if they are not needed. The reason being that protocols can be adopted by class, structs, and enums.

Another reason is that you're providing a default implementation for the protocol in PA, so the PB will only take effect if the method is missing (Which is not because it's already defined in PA).

You can read more about this here.

Sign up to request clarification or add additional context in comments.

3 Comments

While I am sure about the protocol extension not doing the polymorphism part, not so much about the reason, Sealos. If I constraint the protocol type to confirm to only classes, it still exhibits the same behaviour. There is something fundamental to Swift that I am missing. The link explains about the difference in dispatch properties when a func is declared as a requirement and when it's not; nothing about the behaviour exhibited in my case.
When you want to call doSomethingElse on C, it will call the parent's method (Since it inherited from A), and the only information available it's that A conforms to PA, it will use PA's implementation. You should be able to get PB doThis if you call it directly from C. c.doSomethingElse() -> PA implementation, and c.doThis() -> PB
Yes, that's the point. There is no dynamic dispatch going on in this. Fine. Surprise aside, I want to know why that doesn't happen. Any design decisions that prompted the language designers to come up with this? I know for a fact that it isn't because of the protocols being able to conform to all types.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.