108

What is the difference between with and apply. From what I know the following code does the same thing:

swingElement.apply {
    minWidth = ENABLED_COLUMN_WIDTH
    maxWidth = ENABLED_COLUMN_WIDTH
    preferredWidth = ENABLED_COLUMN_WIDTH
}
with(swingElement) {
    minWidth = ENABLED_COLUMN_WIDTH
    maxWidth = ENABLED_COLUMN_WIDTH
    preferredWidth = ENABLED_COLUMN_WIDTH
}

Is there any difference and should I use one over the other? Also, are there some cases where one would work and the other won't?

0

6 Answers 6

108

There're two differences:

  1. apply accepts an instance as the receiver while with requires an instance to be passed as an argument. In both cases the instance will become this within a block.

  2. apply returns the receiver and with returns a result of the last expression within its block.

I'm not sure there can be some strict rules on which function to choose. Usually you use apply when you need to do something with an object and return it. And when you need to perform some operations on an object and return some other object you can use either with or run. I prefer run because it's more readable in my opinion but it's a matter of taste.

Sign up to request clarification or add additional context in comments.

5 Comments

Apply plays better with nullable receivers: foo?.apply { /* maybe do something */ }
Good point. run is not bad too. As for me, with is absolutely useless. I don't use it in my code.
if you like to scope your utility methods inside a top level Object, then with can be useful to bring them into scope for a small code block.
What do you mean by receiver? I cannot find its documentation.
A receiver is an implicit this argument for an extension function: kotlinlang.org/docs/reference/extensions.html
24

Here are the Similarities and Differences

Similarities

With and Apply both accept an object as a receiver in whatever manner they are passed.

Differences

With returns the last line in the lambda as the result of the expression.

Apply returns the object that was passed in as the receiver as the result of the lambda expression.

Examples

With

private val ORIENTATIONS = with(SparseIntArray()) {
    append(Surface.ROTATION_0, 90)
    append(Surface.ROTATION_90, 0)
    append(Surface.ROTATION_180, 270)
    append(Surface.ROTATION_270, 180)
}
ORIENTATIONS[0] // doesn't work 
// Here, using with prevents me from accessing the items in the SparseArray because, 
// the last line actually returns nothing

Apply

private val ORIENTATIONS = SparseIntArray().apply {
    append(Surface.ROTATION_0, 90)
    append(Surface.ROTATION_90, 0)
    append(Surface.ROTATION_180, 270)
    append(Surface.ROTATION_270, 180)
}
ORIENTATIONS[0] // Works
// Here, using apply, allows me to access the items in the SparseArray because, 
// the SparseArray is returned as the result of the expression

2 Comments

This really isn't a great example. The last line of with returns nothing because you wrote it that way. While it wouldn't be great stylistically, you could put this as the last line of with. This is like summing up the differences between a knife and fork by saying "well, the fork isn't very good for cutting".
I think this is a very good example that emphasizes exactly what was discussed. And to be frank, a fork is indeed not very good for cutting. No one has claimed that you can't use it for cutting, but it isn't good at it.
7

The apply function

//returns receiver T, T exposed as `this`
fun <T> T.apply(block: T.() -> Unit): T 

Description

The apply function is invoked on a receiver T, which will be exposed as this in the passed lambda expression. The receiver also becomes the result of apply automatically.

The with function

//return arbitrary value R, not an extension function, T exposed as `this` 
fun <T, R> with(receiver: T, block: T.() -> R): R 

Description

The with function, as opposed to all other scope functions (let, run, also, apply), is not defined as an extension function. Instead, the function is invoked with a receiver object as its first argument explicitly. Same as apply, the receiver is exposed as this in the passed lambda. The result of the lambda, i.e. it’s last statement, becomes the result (R) of with.

2 Comments

I'm guessing OP wanted to know use-case differences like a contextual example to choose one over another rather than a description
@Farid - of course they're wanting to know which is more optimal and for which use case not the documentation copy/pasta'd over.
1

Basically "with" will require one object and that will return only last line. But "apply" do for you like in below example..

val myRectangle = Rectangle().apply {
length = 4
breadth = 5
color = 0xFAFAFA}

This is useful for configuring properties that aren't present in the object constructor.

val obj = with(Turtle()){
    penDown()
    penUp()
    "test"
}
println("test will print "+obj)

Comments

1

Differences

  • Apply: Return the object that passes as an argument
  • With: Return the object in the last line of code
@Test
fun `apply vs with`() {
    val list: MutableList<Int> = mutableListOf<Int>().apply {
        add(1)
        add(2)
        add(3)
    }
    assertEquals(3, list.size)

    val number: Int = with(mutableListOf<Int>()) {
        add(1)
        add(2)
        get(0)
    }
    assertEquals(1, number)
}

When to use apply or with?

Kotlin documentation explains the usages here, but in my opinion, I find it useful when you don't want to type the object repeatedly.

Without apply or with

pluginManager.apply("com.example")
pluginManager.apply("com.android.test")
pluginManager.apply("org.jetbrains.kotlin.android")

With with or apply. Notice that I don't need to type pluginManager three times.

with(pluginManager) {
    apply("com.example")
    apply("com.android.test")
    apply("org.jetbrains.kotlin.android")
}

pluginManager.apply {
    apply("com.example")
    apply("com.android.test")
    apply("org.jetbrains.kotlin.android") 
}

Comments

0

"with(here class reference required)" is used for accessing variable of another class but not for method of that class. Now if we want to use variable and method of another class that time we need to use apply(reference.apply{}) Declare a class like below

class Employee {
    var name:String = ""
    var age:Int = -1

    fun customMethod() {
        println("I am kotlin developer")
    }
}

Now we can access name and age variable of Employee class in onCreate by "with"

val emp = Employee()
with(emp) {
    name="Shri Ram"
    age=30
}
    
println(emp.name)
println(emp.age)}

but we cannot access the "customMethod" of Employee class by with so if we need to use variable along with method, then we need to use "apply":

val emp = Employee()
emp.apply {
    name="param"
    age=30 
}.customMethod()
        
println(emp.name)
println(emp.age)}

Output of with

I/System.out: Shri Ram
I/System.out: 30

Output of apply

I/System.out: I am kotlin developer 
I/System.out: param
I/System.out: 30

1 Comment

This is incorrect and you can also call the method with too.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.