Extension Functions
In this page:
fun Type.functionName(param: Type): ReturnType {
return value // this refers to the receiver
}
value.functionName(argument)
Declaring an Extension Function
An extension function is written as fun Type.name(...), letting you call value.name(...) as if name were a real member of Type, even though Type's own source code was never touched.
Example: Declaring an Extension Function
fun String.shout(): String = this.toUpperCase() + "!"
// Entry point: execution of the program starts here
fun main() {
// Print `"hello".shout()` to the console, with a trailing newline
println("hello".shout())
}
Login to try C/C++/Java/PHP code in the editor
Using this Inside an Extension
Within an extension function's body, this refers to the receiver -- the value the extension was called on -- and can usually be omitted just like in a regular member function.
Example: Using this Inside an Extension
fun Int.isEven(): Boolean = this % 2 == 0
// Entry point: execution of the program starts here
fun main() {
// Print "4 is even: ${4.isEven()}" to the console, with a trailing newline
println("4 is even: ${4.isEven()}")
// Print "7 is even: ${7.isEven()}" to the console, with a trailing newline
println("7 is even: ${7.isEven()}")
}
Login to try C/C++/Java/PHP code in the editor
Extensions on Standard Library Types
Extension functions are especially handy for adding convenient behavior to types you cannot modify directly, including standard library or third-party classes.
Example: Extensions on Standard Library Types
fun List<Int>.secondOrNull(): Int? = if (this.size >= 2) this[1] else null
// Entry point: execution of the program starts here
fun main() {
// Print `listOf(10, 20, 30).secondOrNull()` to the console, with a trailing newline
println(listOf(10, 20, 30).secondOrNull())
// Print `listOf(10).secondOrNull()` to the console, with a trailing newline
println(listOf(10).secondOrNull())
}
Login to try C/C++/Java/PHP code in the editor
Static Resolution of Extensions
Which extension function gets called is decided at compile time based on the declared (static) type of the expression, not the object's actual runtime type -- unlike overridden member functions.
animal is statically typed as Animal, even though it holds a Dog at runtime.Example: Static Resolution of Extensions
open class Animal
// Define a class `Dog`
class Dog : Animal()
fun Animal.describe() = "An animal"
fun Dog.describe() = "A dog"
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `animal` (a `Animal`), set to `Dog()`
val animal: Animal = Dog()
// Print `animal.describe()` to the console, with a trailing newline
println(animal.describe())
}
Login to try C/C++/Java/PHP code in the editor
- Assuming an extension function actually modifies the original class; it is resolved statically and does not change the class itself in any way.
- Expecting extension functions to be polymorphic like member functions; which extension gets called is determined by the declared type at compile time, not the runtime type.
- Forgetting to import an extension function declared in another package, since it must be imported just like any other top-level function.
- An extension function is declared as
fun ReceiverType.functionName(...) { ... }, adding a callable method to an existing type. - Inside the extension,
thisrefers to the receiver instance the function was called on. - Extension functions are resolved statically based on the declared type, not dynamically based on the actual runtime type.
- Extension functions do not actually modify the original class; they are just syntactic sugar for a top-level function call.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: