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.
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.
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
oropen
modifiers are not.
[a short check: Please correct me if Iām wrong. āBothopen
andabstract
members could be declared in abstract classes, the difference is thatopen
can be overridden (but doesnāt need to be), whileabstract
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 implicitlyopen
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) implementationabstract
if there is no implementation
- In interfaces, no
final
members are allowed. - In interfaces, since members are either
open
orabstract
, 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 eitherfinal
(default) oropen
;abstract
members are not allowed) - members in interfaces (members are either
open
orabstract
, depending on the existence of implementation;final
members are not allowed) - members in abstract classes with
open
orabstract
modifiers (members arefinal
(default) oropen
orabstract
)
Is this correct?
Yes. Unless Iām forgetting some edge case this is correct.