Kotlin Scope Function

Learn via video courses
Topics Covered

Overview

Kotlin scope functions are a set of powerful, concise, and expressive tools that allow developers to execute code blocks within a specific context. By leveraging Kotlin scope functions, developers can reduce boilerplate code, streamline common operations on objects and improve the overall efficiency and readability of their programs.

Kotlin Scope Functions

Kotlin scope functions allow developers to execute code blocks within specific contexts, leading to more concise and expressive code. Kotlin scope functions are designed to simplify common operations on objects, reduce the verbosity of code and enhance its readability.

There are five main Kotlin scope functions : let, run, with, apply, and also. The correct choice of Kotlin scope functions can enable you to write concise and expressive code.

Examples of how to use a scope function

Consider the following code snippet without using Kotlin scope functions. Code:

Output:

Now let us write the same program using Kotlin scope function apply .

Code:

Output:

Explanation:

In this program, we use the apply scope function to create and initialize an object of class Student with properties like name, age, and rollNumber.

  1. We define a Student class with three properties: name, age, and rollNumber.
  2. We then create a Student object using the apply scope function. Inside the lambda block of apply, we set the values of the name, age, and rollNumber properties for the Student object.
  3. The apply function returns the Student object itself, which allows us to chain property assignments in a concise manner.
  4. Finally, we print the details of the newly created Student object.

Using the apply scope function in Kotlin in this scenario allowed us to initialize the Student object properties without the need for separate setter methods or multiple lines of code. It not only makes the code more readable and expressive but also reduces the chances of forgetting to initialize any property, as everything is neatly contained within the apply block.

Let us take another example. Consider the following code snippet. Code:

Output:

Now let us write the same program using Kotlin scope function let.

Output:

Explanation:

  1. Since the variable name is nullable, before calling the length function on it, we have to ensure that name is not null else it will throw NullPointerException.
  2. So we use the safe call operator ?. with let. This ensures that the lambda block inside let is only executed if name is not null.
  3. Inside the lambda block of let, the it keyword represents the non-null value of name. We calculate the length of the name string and print it.
  4. If name is null, the safe call ?. ensures that the lambda block is skipped, and the Elvis operator (?:) provides an alternative action, in this case, printing that the Name is null.

In this code, we use the let Kotlin scope function to perform the same task as in the previous code. The code using let is concise & has enhanced readability.

Function selection

Though all the Kotlin scope functions have a structure similar to one another, each of these functions is used for a different purpose. Here's the summary of all the Kotlin scope functions with their important attributes.

FunctionObject referenceReturn valueIs extension function
letitLambda resultYes
runthisLambda resultYes
run-Lambda resultNo: called without the context object
withthisLambda resultNo: takes the context object as an argument
applythisContext objectYes
alsoitContext objectYes

Distinctions

In the table above, we can see the return type to be either Context object or Lambda result. In this section of the article, we will learn more about both of them.

Context Object: The term context object refers to the object on which the scope function is being applied. All Kotlin scope functions, provide a temporary scope in which you can directly access the properties and functions of the context object without explicitly referencing its name.

The Kotlin scope functions can have this or it as the context object.

Return Type: The term return type refers to the type of value that a scope function returns after executing the lambda block. All Kotlin scope functions have a specific behavior regarding its return type, which depends on the last expression inside the lambda block.

The Kotlin scope functions can have context object or last expression inside the lambda block as their return type.

In this part of the article, we have explained the context object and return type of all the Kotlin scope functions:

let scope function in Kotlin

The context object in let is implicitly available as it, which you can use to reference the non-null object within the lambda block. It allows you to perform operations on the non-null context object within the lambda block.

The return type of the let block is determined by the last expression inside the lambda block.

Code:

Output:

apply scope function in Kotlin

The context object in apply is explicitly available as this, which you can use to reference the object itself within the lambda block.

The return type of the apply scope function is the same type as the context object on which it is applied.

Code:

Explanation: In this example, we create a Person object using the apply scope function. The apply block sets the name and age properties of the Person object. The return type of the apply block is the same as the type of the Person object, which is Person.

After the apply block, the person variable holds the modified Person object, and we can see the output as:

Output:

run scope function in Kotlin

The context object in run is represented by the keyword this, which allows you to reference the object itself inside the lambda block.

The return type of the run scope function is the same type as the result of the last expression inside the lambda block.

Code:

Explanation:

In this example, we create a Person object using the run scope function. The run block sets the name and age properties of the Person object, and the last expression is the context object itself (this).

After the run block, the person variable holds the modified Person object, and we can see the output as:

Output:

also scope function in Kotlin

The context object in also is represented by the keyword it. You can use it inside the lambda block to reference the context object.

The return type of the also scope function is the same type as the context object on which it is applied. Like apply, also also returns the context object itself after applying the operations defined in the lambda block.

Code:

Explanation:

In this example, we create a Person object using the also scope function. The also block logs the object's state without modifying the Person object. The also block returns the context object itself (the Person object) as seen in the output below.

Output:

with scope function in Kotlin

The context object in with is represented by the keyword this, which allows you to reference the object itself inside the lambda block.

The return type of the with scope function is the same type as the result of the last expression inside the lambda block.

Code:

Explanation: In this example, we create a Person object using the with scope function. The with block sets the name and age properties of the Person object, and the last expression is the context object itself (this).

After the with block, the person variable holds the modified Person object, and we can see the output as:

Output:

Functions

let scope function in Kotlin

The let scope function in Kotlin is a versatile tool that is particularly useful for working with nullable objects and performing operations on them. It allows you to execute a block of code on a non-null object while avoiding NullPointerExceptions. The primary use cases of the let scope function include:

  • Safe Execution with Nullable Objects: When dealing with nullable objects, let scope function in Kotlin can be used to safely execute code only if the object is not null. It prevents unnecessary code execution when the object is null and helps handle null cases gracefully.

Code:

  • Chain Multiple Operations: You can chain multiple let scope function in Kotlin calls to handle a series of nullable objects in a clean and sequential manner. This makes the code more readable and avoids nested null checks.

Code:

  • Map Nullable Values: let scope function in Kotlin can be used to map nullable values to non-nullable ones or apply default values if the original value is null.

Code:

  • Perform Additional Operations: Besides just accessing the properties of the context object, let scope function in Kotlin allows you to perform additional operations on it and return a custom result based on the logic within the lambda block.

Code:

apply scope function in Kotlin

The apply scope function in Kotlin is used for configuring an object during its initialization. It provides a concise way to set properties and perform other operations on an object without the need for separate setter methods. The primary use cases of the apply scope function include:

  • Object Initialization and Configuration: apply scope function in Kotlin is commonly used to create and initialize an object, configuring its properties in a single scope. It eliminates the need for multiple lines of assignment, resulting in cleaner and more concise code.

Code:

  • Chaining Multiple Operations: apply scope function in Kotlin can be chained with other Kotlin scope functions to execute multiple operations on the same object within a single scope, improving code organization.

Code:

  • Avoiding Temporary Variables: By using apply scope function in Kotlin, you can directly access the properties of the object within the lambda block without creating temporary variables.

Code:

with scope function in Kotlin

The with scope function in Kotlin is used for performing multiple operations on an object without the need to repeatedly reference the object's name. The primary use cases of the with scope function include:

  • Simplified Property Access: with scope function in Kotlin allows you to access properties and call functions of the context object directly without specifying the object's name each time. It improves code readability and reduces redundancy.

Code:

  • Configuring Objects during Initialization: with scope function in Kotlin can be used during object initialization to set multiple properties in a single scope.

Code:

  • Chaining Multiple Operations: with scope function in Kotlin can be chained with other Kotlin scope functions to perform a series of related operations on the same object.

Code:

  • Avoiding Redundant Object Names: with scope function in Kotlin allows you to avoid repeating the object's name multiple times when performing multiple operations on it.

Code:

run scope function in Kotlin

The run scope function in Kotlin combines object initialization and multiple operations on the object. It allows you to execute a series of related actions on the context object within a limited scope. The primary use cases of the run scope function include:

  • Configure Mutable Objects During Initialization: When working with mutable objects, run scope function in Kotlin can help configure the object during initialization, allowing you to perform multiple operations without the need for separate assignments.

Code:

  • Chaining Multiple Operations: run scope function in Kotlin can be chained with other Kotlin scope functions to perform a sequence of operations on the same object.

Code:

  • Use It for Short-lived Variables: When you need a temporary variable for a short duration within a limited scope, you can use run scope function in Kotlin to simplify the code and avoid naming conflicts.

Code:

also scope function in Kotlin

The also scope function in Kotlin is a handy tool for performing additional actions on an object without modifying its properties. It provides a way to execute side effects or auxiliary tasks in a clean and expressive manner. The primary use cases of the also scope function include:

  • Logging or Debugging: also scope function in Kotlin is commonly used for logging or printing the state of an object during its processing or at specific points in the code for debugging purposes.

Code:

  • Side Effects: You can use also scope function in Kotlin to trigger side effects, such as displaying a Toast message, updating a UI component, or performing other actions not directly related to the object's modification.

Code:

  • Interacting with External APIs: also scope function in Kotlin is beneficial when you need to interact with external APIs or perform non-mutating operations on an object, such as data validation.

Code:

  • Chaining with Other Scope Functions: You can chain multiple Kotlin scope functions together to execute a series of actions on the same object, enhancing code organization.

Code:

  • Temporary Variables: When you need a temporary variable for a short duration within a limited scope, you can use also scope function in Kotlin to avoid naming conflicts and improve code readability.

Code:

Output:

takeIf and takeUnless

takeIf and takeUnless are two Kotlin scope functions that allow you to perform conditional checks on an object and optionally execute a block of code based on the result of the check. Both functions are useful when you want to conditionally perform some operation on an object and obtain a result based on the condition.

takeIf

The takeIf function is an extension function that is defined on any type of object and takes a predicate as its argument. The predicate is a function that returns a Boolean value indicating whether the object should be taken or not. If the predicate returns true, takeIf returns the original object; otherwise, it returns null. This can be useful when you want to execute a block of code only when the predicate is true and continue working with the object afterward.

Consider the following code snippet.

Code:

Explanation:

In this example, the takeIf function checks if the number is greater than 10. Since 15 is greater than 10, the block inside the let will be executed, and the output will be "The number is greater than 10: 15".

takeUnless

The takeUnless function is similar to takeIf, but the condition is inverted. It returns the original object if the predicate returns false; otherwise, it returns null. This is useful when you want to execute a block of code only when the condition is false.

Consider the following code snippet.

Code:

Explanation:

In this example, the takeUnless function checks if the number is greater than 10. Since 5 is not greater than 10, the block inside the let will be executed, and the output will be "The number is not greater than 10: 5".

Both takeIf and takeUnless are useful when you want to conditionally handle an object and continue processing it based on the result of the condition.

Conclusion

Here are the key takeaways and advantages of using Kotlin scope functions:

  • let: Use it for performing actions on non-null objects and handling the result with optional transformations.
  • run: Use it for scoping operations, calculating intermediate results, and returning a final value.
  • with: Use it when you want to call multiple functions on the same object.
  • apply: Use it for initializing properties of an object within its constructor.
  • also: Use it for performing actions on objects without affecting their properties or returning a different value.
  • takeIf/takeUnless: Use them for conditional checks and optional processing.