Let vs. with vs. run

There is an excellent review from Cédric Beust about these functions: Exploring the Kotlin standard library, highly recommend reading.

What does `run(f)` give over `f()` or `f.invoke()`

When you have an instance f of a functional type there is not much of use from run, but with functional literal run reads better. Compare for example:

val x = run {   .... // body }

and

val x = {   .... // body }()

Regarding to the question about is there a good reason to keep all three functions we have the following consideration: when such so-called scope function is used with a functional literal it introduces an identifier into the scope of the literal — either this or it, thus it may hide an identifier with the same name from the containing scope.
Despite there are ways to disambiguate hidden identifier, we’d like to provide some flexibility, so that one can choose which form is more convenient in particular situation.

In particular, what would be lost by replacing these methods with the single method below?

fun <T, R> T.with(f: T.(T) -> R): R

First, it hides both this and it in the scope of literal, which may be undesireable. Second, it requires a functional type with two parameters: first is the extension receiver T., second is an extension parameter (T). It's not a big deal for functional literals, but an instance of functional type (T) -> R, which is a function of one parameter, becomes incompatible and therefore could not be passed to such scope function.

1 Like