I want to have a solid understanding of method dispatching in Swift. I read from this popular blog about the three types of dispatches as below:
- Dynamic
- Table(Witness table in Swift)
- Message
In that blog the author says that the NSObject subtypes maintain a dispatch table(witness table) and also a message dispatch hierarchy. The code snippet shared by the author is as below:
class Person: NSObject {
func sayHi() {
print("Hello")
}
}
func greetings(person: Person) {
person.sayHi()
}
greetings(person: Person()) // prints 'Hello'
class MisunderstoodPerson: Person {}
extension MisunderstoodPerson {
override func sayHi() {
print("No one gets me.")
}
}
greetings(person: MisunderstoodPerson()) // prints 'Hello'
I will quote the author's reasoning for the call sayHi() on an instance of Person:
The greetings(person:) method uses table dispatch to invoke sayHi(). This resolves as expected, and “Hello” is printed. Nothing too exciting here. Now, let’s subclass Person
The the author goes on to explain the call sayHi() on an instance of MisunderstoodPerson typecast to Person:
Notice that sayHi() is declared in an extension meaning that the method will be invoked with message dispatch. When greetings(person:) is invoked, sayHi()is dispatched to the Person object via table dispatch. Since the MisunderstoodPerson override was added via message dispatch, the dispatch table for MisunderstoodPerson still has the Person implementation in the dispatch table, and confusion ensues.
I want to know how the author reached to the conclusion that the greetings(person:) method uses table dispatch to invoke sayHi()
One thing that author mentions earlier in the blog is when an NSObject subclass declares a method in the initial declaration(meaning not in extension) a table dispatch would be used.
So I assume that as the parameter 'person' type is Person for the greetings(person:) method and the method called is sayHi() which is declared in the initial declaration of the Person class a table dispatch is used and sayHi() from Person is called. Its safe to say Person witness table is used.
Once we have subclass MisunderstoodPerson and pass this instance to greetings(person:) this instance should be treated as Person. I have a confusion here and have couple of questions here.
- The instance is of type MisunderstoodPerson so would witness table of MisunderstoodPerson be used here.
- Or the instance has been typecast to Person, so would witness table of Person be used here.
The author does not clarify this in the blog as to whose witness tables should be used. Even in some cases I get a feel that author describes even compilers creating witness tables for protocols. It is evident from the image he shares in the blog which is as below.