Skip to content

Beginner: Kotlin · Null safety, functions and lambdas · topic 8 of 50 · 25 min

Extension functions and scope functions

Explanation

An extension function adds a new function to an existing type without changing its code: fun String.initials(). Scope functions (let, run, with, apply, also) run a block of code on an object; they differ in whether the object is it or this inside, and whether they return the object or the block's result. Use them to make code clearer, not cleverer.

Extension functions

Sometimes you wish a type had one more function: String.toTitleCase(), Int.toRupees(). You cannot change the String class, but Kotlin lets you write an extension function: a function declared as if it were inside the type, using the type name before the function name. Inside, this refers to the value it was called on.

kotlin
fun String.initials(): String =
    split(" ").filter { it.isNotBlank() }.map { it[0].uppercaseChar() }.joinToString("")

fun Int.toRupees(): String = "Rs $this"

fun main() {
    println("rahul kumar sharma".initials())   // RKS
    println(499.toRupees())                     // Rs 499
}
They look like built-in methods, but they are ordinary functions behind the scenes.

Extensions do not really change the class and cannot access its private parts. They are resolved at compile time from the variable's declared type. Android libraries use them heavily (for example in Android KTX), so you will see many handy functions that are really extensions.

Extension properties

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

fun main() {
    println("Jai Jawan Jai Kisan".wordCount)   // 4
}
An extension property computes a value; it cannot store data.

Scope functions

Scope functions run a block of code on an object. They exist to make some common patterns shorter: doing something only if a value is not null, configuring an object, or adding a side action like logging. There are five, and they differ in two ways: how you refer to the object inside the block, and what the call returns.

FunctionObject inside blockReturnsTypical use
letitBlock resultRun code on a non-null value: x?.let { }
runthisBlock resultCompute a result from an object
with(obj)thisBlock resultCall several functions on one object
applythisThe object itselfConfigure an object: Builder().apply { }
alsoitThe object itselfSide effects: logging, validation
kotlin
data class Order(var item: String = "", var qty: Int = 0, var note: String = "")

fun main() {
    val order = Order().apply {          // configure: this = the Order
        item = "Paneer tikka"
        qty = 2
    }.also { println("Created $it") }    // side effect, returns the order

    val summary = with(order) { "$qty x $item" }   // compute from it
    val coupon: String? = "FEST10"
    coupon?.let { println("Applying $it") }        // only when not null
    println(summary)
}
apply and also return the object; with and let return the block's result.
Think of it like this: Scope functions are like different ways of handling a file at an office desk. apply is filling in the form and handing back the same form. also is photocopying it for records and handing back the original. let and run are reading the form and giving back a summary note instead.

Choosing one

  • Need to do something only if not null? ?.let.
  • Setting up properties of a new object? apply.
  • Logging or checking without changing the flow? also.
  • Calling many methods on one object and returning a result? with or run.

Common mistakes

  • Nesting scope functions three deep: nobody can tell what this or it means. Use named variables.
  • Using apply when you need the block result (apply always returns the object).
  • Writing extension functions for things that belong in the class you own. Extensions are best for types you cannot change.
  • Expecting an extension to be "overridden" in a subclass. Extensions are chosen by the declared type at compile time.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Extension functions and scope functions · 1/6

fun Int.toRupees() = "Rs $this"

An extension function adds a function to a type you cannot change, like String or Int.

Prefer a video by a teacher? Find free videos on “kotlin extension functions scope functions let apply also run with” on YouTube ↗

In real life: Cleaning form input across an app

A job-portal app receives names, emails and phone numbers from many forms. Instead of repeating cleaning code, the team writes extension functions like String.cleanPhone() and String.isValidEmail() in one file. Every form calls the same functions, and when the phone rule changes (for example to accept +91), one file changes.

kotlin
fun String.cleanPhone(): String = filter { it.isDigit() }.takeLast(10)
fun String.isValidPhone(): Boolean = cleanPhone().length == 10 && cleanPhone()[0] in '6'..'9'

fun main() {
    val typed = "+91 98765-43210"
    println(typed.cleanPhone())      // 9876543210
    println(typed.isValidPhone())    // true
}
Indian mobile numbers have 10 digits and usually start with 6 to 9.

Practice (0/3 done)

Task 1 · Question

What does this print? val sb = StringBuilder().apply { append("Chai") append(" time") } println(sb)

Task 2 · Question

Which scope function returns the result of the block and refers to the object as it?

Task 3 · Practice

Write extension functions: String.isValidPin() (6 digits, not starting with 0), Double.toIndianRupees() (2 decimals with "Rs "), and List<Int>.secondLargest(): Int?. Then use apply to build a data class object and also to print it.

Quick quiz

Question 1

1.Can an extension function access private members of the class it extends?

Question 2

2.Which scope function is best for configuring a newly created object?

Question 3

3.What does also return?

Question 4

4.What is the most common use of ?.let?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Can an extension function access private members of the class it extends?

Answer: No

Extensions are outside the class and only see public members.

Which scope function is best for configuring a newly created object?

Answer: apply

apply returns the object after the setup block.

What does also return?

Answer: The object it was called on

also returns the receiver object.

What is the most common use of ?.let?

Answer: Running code only when a value is not null

x?.let { } skips the block when x is null.

What does an extension method change in the original class?Related

Answer: Nothing; it adds methods usable where the extension is imported

Extensions are compile-time helpers.

From Inheritance, interfaces, mixins and extensions

Which type should a ViewModel expose for screen state?Related

Answer: StateFlow

Read-only, always has a value.

From Interview questions: Kotlin

A variable is declared with const inside a function. Where can it be used?Related

Answer: Only inside that function

let and const are block-scoped: they live only inside their { }.

From Functions

What is the initial value of a global int with no initialiser?Related

Answer: 0

Objects with static storage duration are zero-initialised.

From Scope and storage classes

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Null safety, functions and lambdas”. The module exam comes next.
  2. Module 2 exam: Null safety, functions and lambdas · 13 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Classes, objects and collections. 50 topics left in the course before the final exam.

← Previous: Lambdas and higher-order functions