Extension Properties
In this page:
val Type.propertyName: PropType
get() = expression // this is the receiver
var Type.writable: PropType
get() = expression
set(value) { /* update the receiver */ }
Declaring an Extension Property
An extension property adds a computed property to an existing type, written with a custom get() since there is no way to store an actual backing field for it.
Example: Declaring an Extension Property
val String.firstChar: Char
get() = this[0]
// Entry point: execution of the program starts here
fun main() {
// Print `"Kotlin".firstChar` to the console, with a trailing newline
println("Kotlin".firstChar)
}
Login to try C/C++/Java/PHP code in the editor
Extension Properties Must Be Computed
Because there is no room to add real storage to an existing class, every extension property must derive its value from the receiver each time it is accessed.
Example: Extension Properties Must Be Computed
val List<Int>.average2: Double
get() = if (this.isEmpty()) 0.0 else this.sum().toDouble() / this.size
// Entry point: execution of the program starts here
fun main() {
// Print `listOf(2, 4, 6).average2` to the console, with a trailing newline
println(listOf(2, 4, 6).average2)
}
Login to try C/C++/Java/PHP code in the editor
Writable Extension Properties
A var extension property can define both get() and set(value), letting it behave like a computed read-write property even though it stores no state of its own directly.
Example: Writable Extension Properties
var StringBuilder.lastChar: Char
get() = this[this.length - 1]
set(value) {
this.setCharAt(this.length - 1, value)
}
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `sb`, set to `StringBuilder("Kotlin!")`
val sb = StringBuilder("Kotlin!")
sb.lastChar = '?'
// Print `sb` to the console, with a trailing newline
println(sb)
}
Login to try C/C++/Java/PHP code in the editor
Extension Properties on Custom Types
Extension properties work on your own classes too, which is useful for adding a derived, read-only view of an object's data without modifying the original class.
Example: Extension Properties on Custom Types
// Define a data class `Rectangle`
data class Rectangle(val width: Double, val height: Double)
val Rectangle.area: Double
get() = width * height
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `rect`, set to `Rectangle(4.0, 5.0)`
val rect = Rectangle(4.0, 5.0)
// Print "Area: ${rect.area}" to the console, with a trailing newline
println("Area: ${rect.area}")
}
Login to try C/C++/Java/PHP code in the editor
- Trying to give an extension property a backing field (an initial stored value); extension properties cannot have backing fields, only computed getters (and setters).
- Forgetting an extension
varproperty needs both a customget()andset()since there is no field to default to. - Overusing extension properties for expensive computations, forgetting each access recomputes the value since nothing is cached.
- An extension property is declared as
val/var ReceiverType.propertyName: Type get() = .... - Extension properties cannot have a backing field -- they must be computed through a custom getter (and setter for
var). - Like extension functions, extension properties are resolved statically based on the declared type.
- Extension properties are a clean way to add a derived, read-only fact to an existing type.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: