Sling Academy
Home/Kotlin/When to Use `run` vs. `with` in Kotlin

When to Use `run` vs. `with` in Kotlin

Last updated: November 30, 2024

Kotlin is a modern programming language that provides numerous features to write clean and concise code. Two such features are the run and with functions, which are used to perform operations on an object or set up a block of code. Although they appear similar, each has specific use cases that developers should understand to write effective Kotlin code. This article explores both functions, their differences, and when to use each.

The run Function

The run function is a standard library function in Kotlin used to execute a block of code and return its result. It's an extension function available for all objects in Kotlin, making it versatile for various scenarios. Here’s a basic example:

val result = "Kotlin".run {
    println(this)  // Output: Kotlin
    length
}
println(result)    // Output: 6

In this example, run is called on the string "Kotlin", executes the block, and then returns the length of the string, which is printed as 6.

Use Cases for run

  • Object Initialization: Often used when initializing objects that require several setup steps.
     

    val config = MyConfig().run {
        setup()  // Set up initial configurations
        enableLogging()
        this  // Return the object itself after initialization
    }
  • Executable Lambda: Act as a scope function executing a block of code without needing a preceding object.
     

    val isEligible = run {
        val age = 20
        val citizenship = "US"
        age >= 18 && citizenship == "US"
    }
    println(isEligible)  // Output: true
    

The with Function

The with function, unlike run, is not an extension function. It takes a context object as its first parameter and then applies a block of operations to that object. It returns the result of the block’s last expression.

val list = mutableListOf("A", "B", "C")
with(list) {
    println(size)  // Output: 3
    add("D")
    println(this)  // Output: [A, B, C, D]
}

In the example above, with is used to operate on list, adding elements and printing the result. The context object here is list, and operations within the with block are performed on it.

Use Cases for with

  • Object Configuration: Ideal for cases where successive operations on an object are needed.
     

    val formattedText = with(StringBuilder()) {
        append("Hello, ")
        append("World!")
        toString()
    }
    println(formattedText)  // Output: Hello, World!
    
  • Multiple Object Properties Use: Simplifies operations that involve multiple properties of an object.
     

    class Person(var firstName: String, var lastName: String)
    
    val person = Person("John", "Doe")
    
    val fullName = with(person) {
        "$firstName $lastName"
    }
    println(fullName)  // Output: John Doe
    

Choosing Between run and with

The choice between run and with often depends on the context:

  • run: Use it when you need to operate on an object and still want the block to produce a useful result with 'this' as it context. It's also useful for initializing and configuring an object without an explicit context object.
  • with: Ideal when you have a series of operations related to an object’s properties, especially where the context remains consistently the same, and when readability is enhanced by using a specific object without need of return object.

Understanding these functions illuminates their usefulness in Kotlin and improves code clarity and conciseness.

Next Article: Tail-Recursive Functions: Optimizing Recursion in Kotlin

Previous Article: Using `let` to Avoid NullPointerExceptions in Kotlin

Series: Working with Functions in Kotlin

Kotlin

You May Also Like

  • How to Use Modulo for Cyclic Arithmetic in Kotlin
  • Kotlin: Infinite Loop Detected in Code
  • Fixing Kotlin Error: Index Out of Bounds in List Access
  • Setting Up JDBC in a Kotlin Application
  • Creating a File Explorer App with Kotlin
  • How to Work with APIs in Kotlin
  • What is the `when` Expression in Kotlin?
  • Writing a Script to Rename Multiple Files Programmatically in Kotlin
  • Using Safe Calls (`?.`) to Avoid NullPointerExceptions in Kotlin
  • Chaining Safe Calls for Complex Operations in Kotlin
  • Using the Elvis Operator for Default Values in Kotlin
  • Combining Safe Calls and the Elvis Operator in Kotlin
  • When to Avoid the Null Assertion Operator (`!!`) in Kotlin
  • How to Check for Null Values with `if` Statements in Kotlin
  • Using `let` with Nullable Variables for Scoped Operations in Kotlin
  • Kotlin: How to Handle Nulls in Function Parameters
  • Returning Nullable Values from Functions in Kotlin
  • Safely Accessing Properties of Nullable Objects in Kotlin
  • How to Use `is` for Nullable Type Checking in Kotlin