← Back to Kotlin Course | Chapter 10: Extension Functions & Properties | Lesson 2 of 6

Extension Properties

An extension property lets you add a new labeled fact to an existing type, as long as Kotlin can compute it on the fly instead of storing it directly.
Syntax
kotlin
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

markup
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)
}

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

markup
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)
}

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

markup
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)
}

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

markup
// 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}")
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Trying to give an extension property a backing field (an initial stored value); extension properties cannot have backing fields, only computed getters (and setters).
  2. Forgetting an extension var property needs both a custom get() and set() since there is no field to default to.
  3. Overusing extension properties for expensive computations, forgetting each access recomputes the value since nothing is cached.
Chapter Summary
  • 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:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.