Bird
Raised Fist0
Kotlinprogramming~10 mins

Extensions resolved statically in Kotlin - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Extensions resolved statically
Call extension function on variable
↓
Check variable's declared type
↓
Select extension function based on declared type
↓
Execute selected extension function
↓
Return result
When calling an extension function, Kotlin uses the variable's declared type to decide which function to run, not the actual object type.
Execution Sample
Kotlin
open class Base
class Derived : Base()

fun Base.foo() = "Base"
fun Derived.foo() = "Derived"

val b: Base = Derived()
println(b.foo())
Shows that calling foo() on a Base-typed variable holding a Derived object calls Base's extension.
Execution Table
StepVariableDeclared TypeActual Object TypeExtension Function SelectedOutput
1bBaseDerivedBase.foo()"Base"
2println(b.foo())---Prints "Base"
3End---Execution stops after print
💡 Extension function chosen by declared type 'Base', not actual type 'Derived'
Variable Tracker
VariableStartAfter 1Final
bnullDerived instance (typed as Base)Derived instance (typed as Base)
Key Moments - 2 Insights
Why does b.foo() call Base.foo() even though b holds a Derived object?
Because extension functions are resolved using the variable's declared type (Base), not the actual object type (Derived), as shown in execution_table step 1.
Does Kotlin support polymorphism with extension functions?
No, extension functions are resolved statically at compile time based on declared type, so they do not behave polymorphically like member functions.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, which extension function is called at step 1?
ABase.foo()
BDerived.foo()
CBoth Base.foo() and Derived.foo()
DNo extension function is called
💡 Hint
See execution_table row 1, column 'Extension Function Selected'
At which step does the program print the output?
AStep 1
BStep 2
CStep 3
DNo output is printed
💡 Hint
Check execution_table row 2, column 'Output'
If variable b was declared as Derived instead of Base, which extension function would be called?
ABase.foo()
BBoth Base.foo() and Derived.foo()
CDerived.foo()
DNo extension function would be called
💡 Hint
Extension function depends on declared type, see concept_flow and execution_table step 1
Concept Snapshot
Kotlin extension functions are resolved statically.
They use the variable's declared type, not the actual object type.
This means no polymorphism for extensions.
Example: Base.foo() called on Base-typed variable even if holding Derived.
Remember: extensions are compile-time resolved helpers.
Full Transcript
In Kotlin, when you call an extension function on a variable, the program looks at the variable's declared type to decide which extension function to run. It does not check the actual type of the object stored in the variable. For example, if you have a variable declared as Base but it holds a Derived object, calling an extension function defined for Base will run, not the one for Derived. This is because extension functions are resolved statically at compile time, unlike member functions which are polymorphic. The code example shows a Base.foo() extension and a Derived.foo() extension. When calling foo() on a Base-typed variable holding a Derived object, Base.foo() runs. This behavior is important to understand to avoid confusion about which function runs. Extensions are like helper functions tied to types, not to objects at runtime.

Practice

(1/5)
1. What does it mean that Kotlin extension functions are resolved statically?
easy
A. Extension functions override member functions dynamically.
B. The extension function called depends on the variable's declared type, not the actual object type.
C. The extension function is chosen based on the runtime type of the object.
D. Extension functions can change the original class's source code.

Solution

  1. Step 1: Understand static resolution

    Static resolution means decisions are made at compile time, not runtime.
  2. Step 2: Apply to extension functions

    Kotlin chooses the extension function based on the variable's declared type, ignoring the actual object type.
  3. Final Answer:

    The extension function called depends on the variable's declared type, not the actual object type. -> Option B
  4. Quick Check:

    Extensions resolved statically = based on declared type [OK]
Hint: Remember: extensions use variable type, not object type [OK]
Common Mistakes:
  • Thinking extension functions override member functions dynamically
  • Assuming extension functions change the original class
  • Confusing static with dynamic dispatch
2. Which of the following is the correct syntax to declare an extension function greet for class Person in Kotlin?
easy
A. fun greet() Person { println("Hello") }
B. fun greet(Person) { println("Hello") }
C. extension fun Person.greet() { println("Hello") }
D. fun Person.greet() { println("Hello") }

Solution

  1. Step 1: Recall extension function syntax

    Extension functions use the syntax: fun ClassName.functionName() { ... }
  2. Step 2: Match syntax to options

    fun Person.greet() { println("Hello") } matches the correct syntax: fun Person.greet() { println("Hello") }
  3. Final Answer:

    fun Person.greet() { println("Hello") } -> Option D
  4. Quick Check:

    Extension syntax = fun ClassName.functionName() [OK]
Hint: Extension syntax: fun ClassName.functionName() [OK]
Common Mistakes:
  • Using 'extension' keyword which doesn't exist
  • Incorrect parameter placement
  • Missing receiver type before function name
3. Consider the code:
open class Base
class Derived : Base()

fun Base.foo() = "Base"
fun Derived.foo() = "Derived"

fun printFoo(b: Base) {
    println(b.foo())
}

fun main() {
    val d: Derived = Derived()
    printFoo(d)
}

What is the output when main() runs?
medium
A. Compilation error
B. Derived
C. Base
D. Runtime exception

Solution

  1. Step 1: Analyze parameter type in printFoo

    printFoo takes a parameter of type Base, so inside printFoo, b is of type Base.
  2. Step 2: Understand extension resolution

    Extension functions are resolved statically by the declared type, so b.foo() calls Base.foo(), not Derived.foo().
  3. Final Answer:

    Base -> Option C
  4. Quick Check:

    Extension call depends on declared type = Base [OK]
Hint: Extension call uses parameter type, not actual object type [OK]
Common Mistakes:
  • Expecting Derived.foo() to be called dynamically
  • Confusing extension with member function dispatch
  • Assuming runtime type affects extension resolution
4. Given the code below, what is the error and how to fix it?
open class Animal
class Dog : Animal()

fun Animal.sound() = "Some sound"
fun Dog.sound() = "Bark"

fun main() {
    val animal: Animal = Dog()
    println(animal.sound())
}
medium
A. No error; output is "Some sound"
B. Compilation error: extension functions cannot be overloaded
C. Runtime error: unresolved extension function
D. Output is "Bark" but should be "Some sound"

Solution

  1. Step 1: Check for compilation errors

    Extension functions can be overloaded by receiver type; no syntax error here.
  2. Step 2: Understand output based on static resolution

    Variable animal is declared as Animal, so animal.sound() calls Animal.sound(), outputting "Some sound".
  3. Final Answer:

    No error; output is "Some sound" -> Option A
  4. Quick Check:

    Extension resolved by declared type = Animal.sound() [OK]
Hint: Extensions overload by receiver type; call depends on variable type [OK]
Common Mistakes:
  • Expecting Dog.sound() to be called dynamically
  • Thinking extension functions cause runtime errors
  • Confusing extension overloading with overriding
5. You want to add an extension function describe() to a class hierarchy where Cat inherits from Animal. You want describe() to print "Animal description" when called on an Animal variable, and "Cat description" when called on a Cat variable. Given Kotlin's static resolution of extensions, how should you design your code to achieve this behavior?
hard
A. Declare two extension functions: one for Animal and one for Cat; call describe() on variables typed accordingly.
B. Override describe() as a member function in Cat and Animal classes.
C. Use a when expression inside a single extension function on Animal to check the runtime type.
D. Use reflection to call the correct extension function at runtime.

Solution

  1. Step 1: Understand static resolution impact

    Extension functions are chosen by variable type, so different extensions for Animal and Cat can coexist.
  2. Step 2: Design with two extensions and variable types

    Define describe() extensions for Animal and Cat separately, then call describe() on variables declared as Animal or Cat to get different outputs.
  3. Final Answer:

    Declare two extension functions: one for Animal and one for Cat; call describe() on variables typed accordingly. -> Option A
  4. Quick Check:

    Different extensions + variable types = desired output [OK]
Hint: Use separate extensions and variable types to get different outputs [OK]
Common Mistakes:
  • Trying to override extensions as member functions
  • Relying on runtime type for extension dispatch
  • Using reflection unnecessarily
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard