Chapter 11 of 12 ~12 min read

Extension Functions

Add methods to any class — even ones you don't own, like Java SDK classes or third-party libraries.


The Problem — Java Utility Classes

Java — utility class pattern
// StringUtils.java — helper class
public class StringUtils {
    public static String capitalize(String s) {
        if (s.isEmpty()) return s;
        return Character.toUpperCase(s.charAt(0))
            + s.substring(1);
    }
    
    public static boolean isValidEmail(String email) {
        return email.contains("@") &&
               email.contains(".");
    }
}

// Usage — awkward static call
String result = StringUtils.capitalize("hello");
Kotlin — extension function
// Extension on String — feels native!
fun String.capitalize2(): String {
    if (isEmpty()) return this
    return this[0].uppercaseChar() + substring(1)
}

fun String.isValidEmail() =
    contains("@") && contains(".")

// Usage — called like a member function!
val result = "hello".capitalize2()
val valid  = "test@email.com".isValidEmail()
How it works under the hood

Extension functions are compiled to static utility methods — exactly like your Java utility class. The receiver (this) becomes the first parameter. So "hello".capitalize2() compiles to StringUtils.capitalize2("hello"). No runtime overhead.

Extending Java SDK Classes

Kotlin — extend classes you don't own
// Extend Java's View class
fun View.show() { visibility = View.VISIBLE }
fun View.hide() { visibility = View.GONE }
fun View.invisible() { visibility = View.INVISIBLE }

// Usage — much cleaner than Java!
myButton.show()
myProgressBar.hide()

// Extend Context
fun Context.showToast(msg: String) {
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
}

// In Activity (which is a Context):
showToast("Welcome!")

Extension Properties

Kotlin
// Extension property on String
val String.wordCount: Int
    get() = if (isBlank()) 0 else trim().split(" ").size

"Hello World".wordCount  // 2

// Extension property on Int (dp to px)
val Int.dp: Float
    get() = this * Resources.getSystem()
                            .displayMetrics.density

// Usage in Android UI code:
val margin = 16.dp  // converts dp to px

Nullable Receiver Extensions

Kotlin
// Can even extend nullable types!
fun String?.orDefault(default: String = ""): String {
    return this ?: default
}

val name: String? = null
println(name.orDefault("Anonymous"))  // Anonymous
println(null.orDefault("Guest"))      // Guest
Limitations
  • Extension functions do NOT modify the actual class — they can't access private members
  • If an extension and a member function have the same signature, the member always wins
  • Extensions are resolved statically (at compile time), not dynamically like polymorphism