SyntaxStudy
Sign Up
Kotlin Extension Properties and Members
Kotlin Beginner 1 min read

Extension Properties and Members

Beyond functions, Kotlin also supports extension properties. An extension property behaves like a regular property from the call site but cannot actually store state in the receiver (there is no backing field). It must define a custom getter and, if mutable, a custom setter. Extensions can be declared on companion objects, allowing them to be called with the class name as receiver — a useful pattern for adding factory-like functions to third-party classes without modifying them. You can also declare member extension functions inside a class, which creates a function that has access to both the outer class (this) and the receiver object. This is heavily used in DSL design, where the receiver determines which functions are in scope inside a lambda block.
Example
// Extension property on String
val String.isPalindrome: Boolean
    get() {
        val cleaned = lowercase().filter { it.isLetter() }
        return cleaned == cleaned.reversed()
    }

// Extension property on List
val <T> List<T>.lastIndex: Int
    get() = size - 1

// Extension on companion object (if class has one)
class Matrix(val rows: Int, val cols: Int) {
    companion object
}
fun Matrix.Companion.identity(n: Int): Matrix {
    // returns n×n identity matrix (simplified)
    return Matrix(n, n)
}

// Member extension — DSL pattern
class HtmlBuilder {
    private val sb = StringBuilder()

    fun String.tag(name: String): String {
        sb.append("<$name>$this</$name>")
        return this
    }

    fun build() = sb.toString()
}

fun buildHtml(block: HtmlBuilder.() -> Unit): String {
    val builder = HtmlBuilder()
    builder.block()
    return builder.build()
}

fun main() {
    println("level".isPalindrome)     // true
    println("kotlin".isPalindrome)    // false

    val list = listOf(10, 20, 30)
    println("Last index: ${list.lastIndex}")   // 2

    val m = Matrix.identity(3)
    println("${m.rows}x${m.cols} identity")   // 3x3 identity

    val html = buildHtml {
        "Hello".tag("h1")
        "World".tag("p")
    }
    println(html)   // <h1>Hello</h1><p>World</p>
}