There are several functions in the Kotlin standard library that help in the execution of a block of code within the context of an object. Calling these functions on an object with lambda expression creates a temporary scope. These functions are called Scope Functions. We can access the object of these functions without its name. Sounds confusing! Let’s see an example,
Example: Without using scope function
Kotlin
class Company() {
lateinit var name: String
lateinit var objective: String
lateinit var founder: String
}
fun main() {
val gfg = Company()
gfg.name = "GeeksforGeeks"
gfg.objective = "A computer science portal for Geeks"
gfg.founder = "Sandeep Jain"
println(gfg.name)
}
|
Output:
GeeksforGeeks
Example: Using scope function
Kotlin
class Company() {
lateinit var name: String
lateinit var objective: String
lateinit var founder: String
}
fun main() {
val gfg = Company().apply {
name = "GeeksforGeeks"
objective = "A computer science portal for Geeks"
founder = "Sandeep Jain"
}
println(gfg.name)
}
|
Output:
GeeksforGeeks
Explanation
You must have noticed that when we are not using the scope function, we need to write the object name every time to refer to members of the class. While using the scope function, we can directly refer to members without the object name. This is one of the ways of using the scope function. We will learn more about them in this article.
Scope Functions
Every scope function has well-defined use cases, although all of them have nearly the same outcome. Now let’s look at each scope functions and its use cases:
Application of using scope functions
Scope functions make code more clear, readable, and concise which are Kotlin language’s main features.
Types of scope functions
There are five types of scope functions:
- let
- run
- with
- apply
- also
Each of these functions is quite similar in nature with minor differences. It’s often confusing to decide which function to use and when. So, we need to know what are the differences between these functions and their use cases.
Differences in these functions:
There are mainly two differences among these functions:
- Way of referring to a context object (i.e. using either ‘this’ or ‘it’ keyword)
- return value (i.e. returns either ‘context object’ or ‘lambda result’)
Note: Context object refers to the object on which we are using the scope functions. As in our previous example – ‘gfg’ is our context object
Scope functions table:
Function
|
Object Reference
|
Return Value
|
let
|
it
|
Lambda result
|
run
|
this
|
Lambda result
|
with
|
this
|
Lambda result
|
apply
|
this
|
Context object
|
also
|
it
|
Context object
|
1. let function
Context object : it
Return value : lambda result
Use Case:
let function is often used to provide null safety calls. Use safe call operator(?.) with ‘let’ for null safety. It executes the block only with the non-null value.
Example:
Kotlin
fun main() {
var a: Int? = null
a?.let {
print(it)
}
a = 2
a?.let {
print(a)
}
}
|
Output:
2
Explanation:
As you see when the value of ‘a’ is ‘null’ let function simply avoid the code block. Hence, solving the biggest nightmare of programmers – NullPointerException.
2. apply function
Context object : this
Return value : context object
Use Case:
As the name implies – “Apply these to the object”. It can be used to operate on members of the receiver object mostly to initialize members.
Example:
Kotlin
class Company() {
lateinit var name: String
lateinit var objective: String
lateinit var founder: String
}
fun main() {
Company().apply {
this .founder = "Sandeep Jain"
name = "GeeksforGeeks"
objective = "A computer science portal for Geeks"
}
}
|
3. with function
Context object : this
Return value : lambda result
Use Case:
Recommended use of ‘with’ for calling functions on context objects without providing the lambda result.
Example:
Kotlin
class Company() {
lateinit var name: String
lateinit var objective: String
lateinit var founder: String
}
fun main() {
val gfg = Company().apply {
name = "GeeksforGeeks"
objective = "A computer science portal for Geeks"
founder = "Sandeep Jain"
}
with(gfg) {
println( " $name " )
}
}
|
Output:
GeeksforGeeks
4. run function
Context object : this
Return value : lambda result
‘run’ function can be said as the combination of ‘let’ and ‘with’ functions.
Use Case:
Used when the object lambda contains both initialization and the computation of the return value. Using run we can perform null safety calls as well as other computations.
Example:
Kotlin
class Company() {
lateinit var name: String
lateinit var objective: String
lateinit var founder: String
}
fun main(args: Array<String>) {
println( "Company Name : " )
var company: Company? = null
company?.run {
print(name)
}
print( "Company Name : " )
company = Company().apply {
name = "GeeksforGeeks"
founder = "Sandeep Jain"
objective = "A computer science portal for Geeks"
}
company?.run {
print(name)
}
}
|
Output:
Company Name :
Company Name : GeeksforGeeks
Explanation:
When the ‘company’ value is null, the body of the run is simply ignored. When it is non-null, the body executes.
5. also function
Context object : it
Return value : context object
Use Case:
It is used where we have to perform additional operations when we have initialized the object members.
Example:
Kotlin
fun main() {
val list = mutableListOf<Int>( 1 , 2 , 3 )
list.also {
it.add( 4 )
it.remove( 2 )
}
println(list)
}
|
Output:
[1, 3, 4]
Object References
There are two ways of object referencing in scope functions:
1. this
We can refer to the context object by a lambda receiver keyword – this. this keyword does object reference in ‘run’, ‘with’, and ‘apply’ functions.
Example:
Kotlin
Company().apply {
this .name = "GeeksforGeeks"
this .founder = "Sandeep Jain"
this .objective = "A computer science portal for Geeks"
}
|
Note: We can exclude this keyword to refer to members of the class.
2. it
‘let’ and ‘also’ functions refer to the object’s context as a lambda argument.
Example:
Kotlin
Company().let {
it.name = "GeeksforGeeks"
it.founder = "Sandeep Jain"
it.objective = "A computer science portal for Geeks"
}
|
Return values
There are two types of return values that a scope functions can return:
1. Lambda result
If we write any expression at the end of the code block, it becomes the return value for the scope function. Return value for ‘let’, ‘run’, and ‘with’ functions is the lambda result.
Example:
Kotlin
class Company {
var name: String = "GeeksforGeeks"
var founder: String = "Sandeep Jain"
var objective: String = "A computer science portal for Geeks"
}
fun main() {
val founderName: String = with(Company()) {
founder
}
println( "GfG's Founder : $founderName" )
}
|
Output:
GfG's Founder : Sandeep Jain
2. Context object
‘apply’ and ‘also’ functions return the context object itself. In this case, we don’t need to specify the return value. The context object is automatically returned.
Example:
Kotlin
class Company {
var name: String = "GeeksforGeeks"
var founder: String = "Sandeep Jain"
var objective: String = "A computer science portal for Geeks"
}
fun main() {
val gfg = Company().apply {
}
print( "GfG's Founder : ${gfg.founder}" );
}
|
Output:
GfG's Founder : Sandeep Jain
Summary
- Scope functions make code more readable, clear and concise.
- Object reference – ‘this’ and ‘it’.
- Return value – context object and lambda result.
- let : working with nullable objects to avoid NullPointerException.
- apply : changing object configuration.
- run: operate on nullable object, executing lambda expressions.
- also : adding additional operations.
- with : operating on non-null objects.
Similar Reads
Kotlin functions
In Kotlin, functions are used to encapsulate a piece of behavior that can be executed multiple times. Functions can accept input parameters, return values, and provide a way to encapsulate complex logic into reusable blocks of code. Learn Kotlin Functions What is Functions?Example of a FunctionType
8 min read
Local Functions in Kotlin
The idea behind functions is very simple: split up a large program into smaller chunks that can be reasoned more easily and allow the reuse of the code to avoid repetition. This second point is known as the DRY principle: Don't Repeat Yourself. The more the number of times you write the same code, t
5 min read
Kotlin Higher-Order Functions
Kotlin language has superb support for functional programming. Kotlin functions can be stored in variables and data structures, passed as arguments to and returned from other higher-order functions. Higher-Order Function - In Kotlin, a function which can accept a function as parameter or can return
6 min read
Introduction to Kotlin
Kotlin is a statically typed, general-purpose programming language developed by JetBrains, that has built world-class IDEs like IntelliJ IDEA, PhpStorm, Appcode, etc. It was first introduced by JetBrains in 2011 and a new language for the JVM. Kotlin is object-oriented language, and a "better langua
4 min read
Kotlin Inline Functions
In Kotlin, the higher-order functions or lambda expressions, all stored as an object so memory allocation, for both function objects and classes, and virtual calls might introduce runtime overhead. Sometimes we can eliminate the memory overhead by inlining the lambda expression. In order to reduce t
5 min read
Kotlin for loop
In Kotlin, for loop is equivalent to foreach loop of other languages like C#. Here for loop is used to traverse through any data structure which provides an iterator. It is used very differently then the for loop of other programming languages like Java or C. The syntax of for loop in Kotlin: for(it
4 min read
Kotlin infix function notation
In this article, we will learn infix notation used in Kotlin functions. In Kotlin, a functions marked with infix keyword can also be called using infix notation means calling without using parenthesis and dot. There are two types of infix function notation in Kotlin- Standard library infix function
5 min read
Suspend Function In Kotlin Coroutines
Prerequisite: Kotlin Coroutines on Android The Kotlin team defines coroutines as âlightweight threadsâ. They are sort of tasks that the actual threads can execute. Coroutines were added to Kotlin in version 1.3 and are based on established concepts from other languages. Kotlin coroutines introduce a
4 min read
Kotlin extension function
Kotlin gives the programmer the ability to add more functionality to the existing classes, without inheriting them. This is achieved through a feature known as extensions. When a function is added to an existing class it is known as Extension Function. To add an extension function to a class, define
5 min read
Triple in Kotlin
In programming, we call functions to perform a particular task. The best thing about function is that we can call it any number of times and it returns some value after computation i.e. if we are having add() function then it always returns the sum of both the numbers entered. But, functions have so
4 min read