What is with function for?

I’ve seen a lot of discussion of Kotlin combinators, but cannot find any clear description of what would be lost if the standard library didn’t include with. It seems that every use of with could be replaced with run.

In general also and apply, let and run as well as with are very similar.
also and apply return the receiver while the rest return the result of the block, but if you really want you could use any one of the last 3 and remove the rest.
So why have all 5 of them?

I think it’s easy to justify the first 4. You want to have blocks that return either the receiver or the result and you also want to be able to use either it or the implicit this.

with is different. It does not fit in with the others as easily. I personally like to use it to specify context switches. It’s not about the generated bytecode (which is the same for all 5 functions, as they all should generate no bytecode at all). It’s about what I want to express. For me the difference between run and with is more about, do I want to run some functions on an object or do I feel it’s more the object running the functions (I hope this makes sense). Also I like to use with when calling extension functions that are only part of some class:

class Bar
class Foo {
    fun Bar.foo() 
}

val b = Bar()
val f = Foo()
with(f){   // You could use run here, but I feel with is more expressive
    b.foo()
}

I hope this all makes sense. I feel it depends on the context whether I like with or run more. Also this is just my personal opinion and should not be taken as any style-guide :wink:

1 Like

The goal isn’t no duplicate functions, the goal is readability and writability. I often choose the with function because it’s more readable in some cases compared to run.

1 Like

I use ‘with’ for extension functions that need more than one receiver when some of those receivers are not in scope.

class A {
  fun B.foo() = Unit
}

class B {
  val a = A()

  fun bar() = with(a) {
    foo()
  }
}

In order to invoke foo(), both objects ‘a’ and ‘b’ are equally important. Using run instead of with would give more importance to the variable/object ‘a’ than it deserves in this case.

It is interesting how people hate with in JavaScript but override the this context in Kotlin all the time.

The difference to JS is that Kotlin is statically typed. The arguments against JS ‘with’ statement can partially be applied to Kotlin, too. But in Kotlin the bad things would usually happen at compilation time, not at runtime. Also, because of the static typing you can ask the IDE what is going on within a with function.