What does the term "dispatch" and "virtual" mean in the documentation?

Extensions are resolved statically

Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on variables of this type.

We would like to emphasize that extension functions are dispatched statically, i.e. they are not virtual by receiver type. This means that the extension function being called is determined by the type of the expression on which the function is invoked, not by the type of the result of evaluating that expression at runtime.

2 Likes

Do you know the difference between compile-time type and runtime type of a variable?

I recently got to know the existence of those concepts, and I think I know vaguely what it is.

open class Shape

class Rectangle: Shape()

fun Shape.getName() = "Shape"

fun Rectangle.getName() = "Rectangle"

fun printClassName(s: Shape) {
    println(s.getName())
}    

printClassName(Rectangle())

From my understanding, in function printClassName, its parameter variable s 's compile-time (static) type would be Shape, whereas when printClassName(Rectangle()) is run, in s.getName(), the runtime (dynamic) type of variable s would be Rectangle. But I donā€™t know that deeply how this is done.

So far so good. This difference is important when you want to understand the difference between static and dynamic dispatch.

Static dispatch means the function is resolved at compile-time to the receiverā€™s static typeā€™s function. The function cannot be overridden by subtypes. The function can sure be defined in subtypes, but they will not be invoked.

Dynamic dispatch means the function is resolved at runtime to the receiverā€™s dynamic typeā€™s function. The function can be overridden by subtypes. Overridable functions are also called virtual functions.

2 Likes

Thanks for the explanation.

So then in Kotlin, are all open functions ā€œvirtualā€ functions? Is it correct to say that

  • functions in normal classes with open inheritance modifier
  • functions defined in interfaces
  • functions defined abstract classes

are all ā€œvirtualā€? (all members of interfaces or abstract classes are implicitly open, or am I wrong?)

Thatā€™s my exact understanding of it. If I remember correctly, C++ has a virtual keyword. When I am not mistaken it has the same meaning as ā€œopenā€ in Kotlin (in function declarations).

More exactly, I donā€™t know whether a missing virtual keyword will prevent a function to be redeclared in a subclass in C++. But I am sure it will not be overridden in a polymorphic manner.

In Kotlin a missing open keyword does not only prevent overriding it, it also prevents redeclaring it in a subclass.

Functions in abstract classes still require open to be virtual.
You can ā€˜foldā€™ this bullet point into your first one: ā€œclasses with open modifierā€

The abstract keyword will also mark a method as virtual. And all those rules apply the same way for properties.

I guess my understanding about the abstract classes still have many holes.
Let me try to re-summarize after reading @al3c and @Wasabi375 's reply to see if I understood correctly.

  • In abstract classes, not ALL methods are ā€œvirtualā€ i.e. methods without abstract or open modifiers are not.
    [a short check: Please correct me if Iā€™m wrong. ā€œBoth open and abstract members could be declared in abstract classes, the difference is that open can be overridden (but doesnā€™t need to be), while abstract MUST be overridden.ā€]

  • In abstract classes, methods without an explicit inheritance modifier keyword are implicitly final by default, unlike the case for interfaces where the members are implicitly open by default.

PLUS, Iā€™d like some additional checks about interfaces:

  • In interfaces, members without an explicit inheritance modifier are implicitly
    • open if there is a function implementation or accessor(getter/setter) implementation
    • abstract if there is no implementation
  • In interfaces, no final members are allowed.
  • In interfaces, since members are either open or abstract, they are all ā€œvirtualā€

If I rephrase this again, the ā€œvirtualā€(overridable) members would be among the following

  • members(functions or properties) in normal classes with open inheritance modifier (members are either final(default) or open; abstract members are not allowed)
  • members in interfaces (members are either open or abstract, depending on the existence of implementation; final members are not allowed)
  • members in abstract classes with open or abstract modifiers (members are final(default) or open or abstract)

Is this correct?

Yes. Unless Iā€™m forgetting some edge case this is correct.