Kotlin Extension Functions

An extension function adds a new function to an existing class without modifying the class source code. You write it outside the class, but it looks and behaves like a regular member of that class. This is one of the most powerful and practical features of Kotlin.

The Problem Extension Functions Solve

Imagine you want a function that checks whether a String is a valid email address. The String class does not have this built in. Without extension functions, you would write a utility function and call it like this:

// Utility style — awkward
fun isValidEmail(email: String): Boolean {
    return email.contains("@") && email.contains(".")
}

val email = "user@estudy247.com"
println(isValidEmail(email))   // true

With an extension function, the same logic feels like it belongs to String:

// Extension function — natural and readable
fun String.isValidEmail(): Boolean {
    return this.contains("@") && this.contains(".")
}

val email = "user@estudy247.com"
println(email.isValidEmail())   // true

Syntax of an Extension Function

fun ReceiverType.functionName(parameters): ReturnType {
    // 'this' refers to the receiver (the object the function is called on)
}

fun String.shout(): String {
    return this.uppercase() + "!!!"
}

println("hello".shout())    // HELLO!!!
println("kotlin".shout())   // KOTLIN!!!

Diagram — How Extension Functions Work

"hello".shout()
   │         │
   │         └─ Extension function defined on String
   └─ Receiver: the String instance ("hello")
                Inside the function, 'this' = "hello"

Output: "HELLO!!!"

Practical Extension Function Examples

Int Extensions

fun Int.isEven(): Boolean = this % 2 == 0
fun Int.square(): Int = this * this
fun Int.isPrime(): Boolean {
    if (this < 2) return false
    for (i in 2..this / 2) if (this % i == 0) return false
    return true
}

println(6.isEven())    // true
println(7.square())    // 49
println(13.isPrime())  // true

String Extensions

fun String.toTitleCase(): String {
    return this.split(" ").joinToString(" ") { word ->
        word.lowercase().replaceFirstChar { it.uppercase() }
    }
}

fun String.removeSpaces(): String = this.replace(" ", "")

println("the quick brown fox".toTitleCase())   // The Quick Brown Fox
println("  k o t l i n  ".removeSpaces())      // kotlin

List Extensions

fun List.secondOrNull(): Int? = if (this.size >= 2) this[1] else null

fun List.printAll() {
    this.forEachIndexed { i, item -> println("${i + 1}. $item") }
}

val nums = listOf(10, 20, 30)
println(nums.secondOrNull())   // 20

val courses = listOf("Kotlin", "Android", "Jetpack")
courses.printAll()
// 1. Kotlin
// 2. Android
// 3. Jetpack

Extension Properties

You can also add properties to existing classes using extension properties. These cannot store state — they compute their value each time.

val String.wordCount: Int
    get() = this.trim().split("\\s+".toRegex()).size

val Int.isNegative: Boolean
    get() = this < 0

println("Hello Kotlin World".wordCount)   // 3
println((-5).isNegative)                  // true

Extension Functions on Nullable Types

fun String?.orUnknown(): String {
    return this ?: "Unknown"
}

val name: String? = null
println(name.orUnknown())    // Unknown

val city: String? = "Delhi"
println(city.orUnknown())    // Delhi

Extensions vs Member Functions

class Greeter {
    fun greet() = println("Member greet!")          // member function
}

fun Greeter.greet() = println("Extension greet!")   // extension function

Greeter().greet()   // Member greet! — member wins when names conflict

When a member function and an extension function have the same name, the member function always takes priority.

When to Use Extension Functions

Scenario                                         | Use Extension Function?
-------------------------------------------------|------------------------
Add helper to a class you wrote                  | Maybe (consider member fn)
Add helper to a library class (String, List)     | Yes
Add helper to a class from a 3rd-party library   | Yes (cannot modify source)
Group related utilities without a Util class     | Yes

Leave a Comment

Your email address will not be published. Required fields are marked *